安卓8.0奥利奥 - 账户

7
在我的应用程序中,我需要知道是否存在任何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 部分中的 Account Access and Discoverability

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

我找到了一些资料,声称现在唯一访问账户的方法是像这样使用 AccountPicker

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

但这确实回答了我的问题。明确地说,我只需要知道某种类型的帐户是否存在(Google,三星...),我不需要知道有多少个,也不需要帐户信息。


“这不再起作用”是什么意思?您能提供一些代码、日志或堆栈跟踪,无论对您来说似乎相关的内容,以便社区能够帮助您吗? - Benjamin
我的意思是getAccount()方法不再返回除与应用程序链接的帐户之外的帐户数据。 - Steeve Favre
以下是官方文档的更多细节说明:在Android 8.0(API级别26)中,应用程序不能再访问用户帐户,除非验证器拥有这些帐户或用户授权该访问。 - Steeve Favre
@Steeve Favre,您能分享相关链接并告诉我如何解决这个问题吗? - Nikhil Singh
请看我的回答。这是让它工作的方法。 - AndyB
这里提供了详细的方法:https://stackoverflow.com/a/53693072/6886397 - Vasudevan Nair R
3个回答

6

使用 "android.permission.READ_CONTACTS" 权限,以及

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

在安卓 Oreo 中再次工作


5
正如你所说,如果用户没有给你权限,那么你就没有办法读取其他帐户。现在提供的权限不仅是运行时权限,而且还有帐户选择器,即仅当用户在调用帐户选择器之后选择了帐户时,该帐户才对您的应用程序可见。这种新限制的目的正是为了避免你试图做的事情:读取所有用户帐户。你的问题没有解决方案,你唯一能做的就是向用户呈现选择器,并让他选择所有帐户,虽然这不是最佳的用户体验。
编辑:从Google Play服务11.6开始,现在有一个新方法requestGoogleAccountsAccess()可以获取所有Google帐户。

正如我所说,我不想阅读任何关于账户的信息。我只需要知道某种类型的账户是否存在。但我猜你是对的,即使对于这个问题也没有解决方案。 - Steeve Favre
我知道现在已经晚了,所以我只会为未来的读者发布。了解帐户是否存在仍然是您需要访问获取的信息。例如:用户可能不希望您知道哪些帐户存在,因为帐户的存在本身就是私人信息。 - Aaron T Harris
@AaronTHarris,您能告诉我如何解决这个问题吗?我该如何从已链接的 Google 帐户中获取用户名称。 - Nikhil Singh
请看我的回答。这是让它正常工作的方法。 - AndyB

1
要获取运行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);
        }
    }
}

谷歌为什么要决定使用这种“架构”,而不是返回一个Task等,这有点奇怪。但是这就是让它工作的方法。

当然,这段代码需要适当的异常处理,为了可读性我没有包含在内。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接