Account access and discoverability (계정 액세스 및 검색 가능 여부)
인증자가 계정을 소유하고 있거나 사용자가 계정 액세스 권한을 허용하지 않은 경우 앱이 더 이상 사용자 계정에 액세스 할 수 없습니다. 이제 GET_ACCOUNTS 권한만으로는 충분하지 않습니다. 앱이 계정에 액세스 권한을 얻으려면 AccountManager.newChooseAccountIntent() 또는 인증자의 특정한 메소드를 사용해야 합니다. 계정에 대한 액세스 권한을 얻은 후에는 앱이 AccountManager.getAccounts() 를 호출하여 계정에 액세스 할 수 있습니다.
Android O는 LOGIN_ACCOUNTS_CHANGED_ACTION의 지원을 중단합니다. (deprecated) 대신에 앱은 addOnAccountsUpdatedListener()를 사용하여 런타임 중에 계정에 대한 업데이트를 얻어야 합니다.
New account access and discovery APIs
Android O에서는 앱이 사용자 계정에 액세스하는 방식을 여러 가지로 개선합니다. 인증자는 자신이 관리하는 계정을 어떤 앱에는 숨기고 어떤 앱에는 표시할지 여부를 결정하기 위해 고유한 정책을 사용할 수 있습니다.
이전의 Android 버전에서 사용자 계정 목록을 추적하려는 앱은 관련 없는 유형의 계정을 포함하여 모든 계정을 업데이트 해야 했습니다. Android O에서는 addOnAccountsUpdatedListener 메서드가 추가되었습니다. 이 메서드를 사용하는 앱은 계정 변경 사항을 수신해야 하는 계정 유형 목록을 지정할 수 있습니다.
API 변경 사항
AccountManager는 인증자가 계정을 볼 수 있는 앱을 관리하도록 도와주는 6개의 새로운 메서드를 제공합니다.
-
setAccountVisibility 특정 사용자 계정과 패키지 조합의 가시성 수준을 설정합니다.
-
getAccountVisibility 특정 사용자 계정과 패키지 조합의 가시성 수준을 가져옵니다.
-
getAccountsAndVisibilityForPackage 인증자가 주어진 패키지의 계정과 가시성 수준을 가져올 수 있습니다.
-
getPackagesAndVisibilityForAccount 인증자가 주어진 계정의 저장된 가시성 값을 가져올 수 있습니다.
-
addAccountExplicitly 인증자가 계정의 가시성 값을 초기화할 수 있습니다.
-
addOnAccountsUpdatedListener AccountManager 객체에 OnAccountsUpdateListener를 추가합니다. 디바이스의 계정 목록이 변경되었을 때 리스너를 호출합니다.
Android O는 setAccountVisibility 메소드를 사용하여 설정되지 않은 어플리케이션의 가시성 수준을 지정하는 두개의 특별한 Package Name 값을 도입합니다.
PACKAGE_NAME_KEY_LEGACY_VISIBLE 은 GET_ACCOUNTS 권한이 있고 Android O 보다 낮은 Android 타겟 버전이거나 인증자와 서명이 일치하는 앱에 적용됩니다.
PACKAGE_NAME_KEY_LEGACY_NOT_VISIBLE은 앱이 이전에 설정되지 않았고 PACKAGE_NAME_KEY_LEGACY_VISIBLE이 적용되지 않은 앱에 기본 가시성 값으로 제공합니다.
테스트
Android O가 설치된 디바이스에서 target version이 26인 앱으로 계정 목록을 요청했을 때 google 계정은 읽을 수 없습니다. 아직 target version이 26이 아닌 계정 (facebbok, naver, payco 등)은 정상적으로 계정 정보를 얻어올 수 있습니다.
- Code
AccountManager accountManager = AccountManager.get(this);
Account[] accounts = accountManager.getAccounts();
for (Account account : accounts) {
String accountName = account.name;
String accountType = account.type;
Log.d(TAG, "Account Name: " + accountName);
Log.d(TAG, "Account Type: " + accountType);
}
- Android N (Target 25 or 26)
Account Name: shnoble79@gmail.com
Account Type: com.google
Account Name: shnoble79@gmail.com
Account Type: com.facebook.auth.login
Account Name: shnoble79
Account Type: com.nhn.android.naveraccount
- Android O (Target 25)
Account Name: shnoble79@gmail.com
Account Type: com.google
Account Name: shnoble79@gmail.com
Account Type: com.facebook.auth.login
Account Name: shnoble79
Account Type: com.nhn.android.naveraccount
- Android O (Target 26)
// 구글 계정을 가져올 수 없습니다.
Account Name: shnoble79@gmail.com
Account Type: com.facebook.auth.login
Account Name: shnoble79
Account Type: com.nhn.android.naveraccount
Google 계정 정보를 가져오기
Android O 디바이스, Target 26으로 설정된 앱에서 Google 계정 정보를 가져오려면 newChooseAccountIntent() 메서드를 사용하여 해당 계정의 권한을 얻어야 합니다.
private void chooseAccountIntent() {
Intent intent = AccountManager.newChooseAccountIntent(
null, null, new String[]{"com.google"}, null, null, null, null);
startActivityForResult(intent, REQUEST_CODE);
}
...
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_CODE) {
if (data != null) {
Bundle extras = data.getExtras();
final String accountName = extras.getString(AccountManager.KEY_ACCOUNT_NAME);
final String accountType = extras.getString(AccountManager.KEY_ACCOUNT_TYPE);
Log.d(TAG, "Account Name: " + accountName);
Log.d(TAG, "Account Type: " + accountType);
}
}
}
newChooseAccountIntent() 메서드의 minSdkVersion은 23 이상입니다.
newChooseAccountIntent() 메서드를 사용하여 startActivityForResult를 호출하면 아래와 같이 계정 선택 창이 노출됩니다.
Google 인증 토큰 가져오기
AccountManager accountManager = AccountManager.get(MainActivity.this);
AccountManagerFuture<Bundle> accountManagerFuture = accountManager.getAuthToken(new Account(accountName, accountType), "ah", null, MainActivity.this, null, null);
Bundle authTokenBundle = null;
try {
authTokenBundle = accountManagerFuture.getResult();
} catch (OperationCanceledException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (AuthenticatorException e) {
e.printStackTrace();
}
if (authTokenBundle != null) {
String authToken = authTokenBundle.get(AccountManager.KEY_AUTHTOKEN).toString();
Log.d(TAG, "Account Auth Token: " + authToken);
} else {
Log.d(TAG, "Account Auth Token is null");
}