Android 8.0 Oreo - 账户

Android 8.0 Oreo - Accounts

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

最多 Android 7 可以通过以下方式轻松获取此信息:

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

但是随着 Oreo 事件的发生,这不再有效了。

编辑:查看有关此主题的官方信息: 在 Android 8.0(API 级别 26)中,应用无法再访问用户帐户,除非验证器拥有帐户或用户授予该访问权限。 GET_ACCOUNTS 权限不再足够。要获得帐户访问权限,应用程序应使用 AccountManager.newChooseAccountIntent() 或特定于身份验证器的方法。获得帐户访问权限后,应用程序可以调用 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,三星...)我不需要知道有多少,也不需要帐户信息。

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

编辑:从 Google Play Services 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() 抛出一个异常,您可以将其(检查后)投射到 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);
        }
    }
}

有点奇怪为什么Google自己决定了这个"architecture"。为什么不 return 任务等。 但这就是你让它工作的方式。

当然,这段代码需要适当的异常处理,为了便于阅读,我省略了这一点。