Android 8.0 Oreo – 帐户

在我的应用中,我需要知道是否有任何Google帐户或任何三星帐户。

直到Android 7,很容易获得这样的信息:

Account[] accounts = AccountManager.get(getContext()) .getAccountsByType("com.google") 

但随着Oreo事件的发生,这种情况不再适用。

编辑:查看有关此主题的官方信息: 在Android 8.0(API级别26)中,除非身份validation者拥有帐户或用户授予该访问权限,否则应用程序将无法再访问用户帐户。 GET_ACCOUNTS权限已不再足够。 要授予对帐户的访问权限,应用应使用AccountManager.newChooseAccountIntent()或特定于身份validation器的方法。 访问帐户后,应用程序可以调用AccountManager.getAccounts()来访问它们。 Android 8.0弃用了LOGIN_ACCOUNTS_CHANGED_ACTION。 应该使用addOnAccountsUpdatedListener()代替应用程序在运行时获取有关帐户的更新。 有关为帐户访问和可发现性添加的新API和方法的信息,请参阅本文档新API部分中的帐户访问和可发现性

我花了半天时间找到解决方案,但没有成功。

我发现信息声称现在访问帐户的唯一方法是使用AccountPicker如下所示:

 AccountPicker.newChooseAccountIntent(null, null, new String[]{"com.google"},true, null, null, null, null); 

但这确实回应了我的问题。 为了清楚起见,我只需要知道某个类型的帐户是否存在(Google,三星……)我不需要知道多少,如果是这样,也不需要帐户信息。

正如您已经说过的,如果用户未授予您许可,则无法读取其他帐户。 现在,权限不仅提供了运行时权限,而且还提供了帐户选择器,即只有在您调用帐户选择器后用户选择了帐户时,您的应用才能看到帐户。 这个新限制正是为了避免您尝试做的事情:阅读所有用户帐户。 您的问题没有解决方案,您唯一能做的就是将选择器呈现给用户并让他选择所有帐户,而不是最佳用户体验。

编辑:从Google Play服务11.6开始,现在有一个新方法requestGoogleAccountsAccess()来获取所有Google帐户。

使用“android.permission.READ_CONTACTS”权限,和

  Account[] accounts = AccountManager.get(getContext()) .getAccountsByType("com.google") 

在android Oreo再次工作

使用此代码在运行Oreo +(8+)的设备上获取已安装的Google帐户

  Account[] accounts = AccountManager.get(getContext()).getAccountsByType("com.google") 

你需要先打电话

https://developers.google.com/android/reference/com/google/android/gms/auth/GoogleAuthUtil.html#requestGoogleAccountsAccess(android.content.Context)

请先添加以下依赖项

 com.google.android.gms:play-services-auth:16.0.0 

调用requestGoogleAccountsAccess()会抛出一个exception,您可以将其转换(检查后)到UserRecoverableAuthException并从中获取一个startActivityForResult的意图

以下是一些示例代码,适用于Android Oreo

 // call this on a background thread! private void requestGoogleAccountAccess() throws Exception { googleAccountAccessGranted = GoogleAuthUtil.requestGoogleAccountsAccess(this); Log.i(TAG, "googleAccountAccessGranted: " + googleAccountAccessGranted); } // exception handler after calling method above private void handleAuthResult(Throwable e) { if (e instanceof UserRecoverableAuthException) { UserRecoverableAuthException authException = (UserRecoverableAuthException) e; startActivityForResult(authException.getIntent(), AUTH_PERMISSION_REQUEST); } else { Log.e(TAG, "Cannot request Google Account Access", e); } } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == AUTH_PERMISSION_REQUEST) { Log.i(TAG, "Google Auth Permission Result"); if (resultCode == Activity.RESULT_CANCELED) { Log.w(TAG, "User Cancelled Play Services Auth Request.") } else if (resultCode == Activity.RESULT_OK) { Log.d(TAG, "User accepted Play Services Auth Request."); // call the following line again on a background thread. the call now returns a boolean instead of throwing an exception // googleAccountAccessGranted = GoogleAuthUtil.requestGoogleAccountsAccess(this); } } } 

谷歌为什么要为这个“架构”做出决定,这有点奇怪。 为什么不返回任务等等。但这就是你如何使它工作。

当然,这段代码需要适当的exception处理,为了便于阅读,我将其遗漏。