AccountManager.getAccounts()在targetSdk>23环境下失效问题咨询
解决API26+下AccountManager.getAccounts()返回空数组的问题
你遇到的这个问题其实是Android 8.0(API26)之后Google对账号访问权限的收紧导致的——不仅运行时权限规则变了,AccountManager.getAccounts()这个方法本身也被限制了,第三方应用再也没法通过它获取Google类型的账号信息了。下面给你推荐官方认可的、无需用户再次登录的解决方案:
核心原因说明
- 在API23之前,
GET_ACCOUNTS是普通权限,安装时自动授予,所以getAccounts()能正常返回账号; - API23开始,
GET_ACCOUNTS变成危险权限,需要动态申请,但此时还能获取到Google账号; - 到API26,Google直接限制了第三方应用对Google账号的访问:即使你申请了
GET_ACCOUNTS,getAccounts()也只会返回非Google的账号,甚至空数组。同时这个方法也被标记为过时,官方不推荐再使用。
推荐解决方案:使用Google Sign-In静默登录
官方推荐用Google Sign-In API来获取已登录用户的信息,其中的silentSignIn()方法可以在用户已经登录过Google账号且授权过你的应用时,直接返回用户信息,完全不需要用户再次操作。
步骤1:添加依赖
在你的Module级别build.gradle中添加Google Sign-In的依赖:
implementation 'com.google.android.gms:play-services-auth:20.7.0'
步骤2:初始化客户端并执行静默登录
在你的Activity或Fragment中,初始化GoogleSignInClient并调用静默登录:
private static final int RC_SIGN_IN = 1001; private GoogleSignInClient mGoogleSignInClient; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 配置SignIn选项,请求邮箱、用户名和头像信息 GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN) .requestEmail() .requestProfile() .build(); // 初始化客户端 mGoogleSignInClient = GoogleSignIn.getClient(this, gso); // 执行静默登录 Task<GoogleSignInAccount> silentSignInTask = mGoogleSignInClient.silentSignIn(); silentSignInTask.addOnCompleteListener(this, task -> { if (task.isSuccessful()) { // 成功获取用户信息 GoogleSignInAccount account = task.getResult(); String userName = account.getDisplayName(); String userEmail = account.getEmail(); Uri avatarUri = account.getPhotoUrl(); // 这里更新你的Drawer布局 updateDrawerUserInfo(userName, userEmail, avatarUri); } else { // 静默登录失败,说明用户未登录或未授权,需要引导用户登录 Intent signInIntent = mGoogleSignInClient.getSignInIntent(); startActivityForResult(signInIntent, RC_SIGN_IN); } }); }
步骤3:处理登录回调(如果静默失败)
如果静默登录失败,用户需要手动登录,我们需要处理登录结果:
@Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == RC_SIGN_IN) { Task<GoogleSignInAccount> task = GoogleSignIn.getSignedInAccountFromIntent(data); handleSignInResult(task); } } private void handleSignInResult(Task<GoogleSignInAccount> completedTask) { try { GoogleSignInAccount account = completedTask.getResult(ApiException.class); // 再次获取信息并更新Drawer String userName = account.getDisplayName(); String userEmail = account.getEmail(); Uri avatarUri = account.getPhotoUrl(); updateDrawerUserInfo(userName, userEmail, avatarUri); } catch (ApiException e) { Log.w("DrawerAuth", "登录失败,错误码:" + e.getStatusCode()); // 这里可以给用户提示登录失败 } }
步骤4:必要的权限配置
在AndroidManifest.xml中添加网络权限(因为需要和Google服务器交互):
<uses-permission android:name="android.permission.INTERNET" />
额外注意事项
- 你需要在Google Cloud Console中为你的应用配置OAuth 2.0客户端ID,否则登录会失败;
- 如果你的应用只需要获取账号基本信息(用户名、邮箱、头像),
DEFAULT_SIGN_IN配置完全足够,不需要额外申请Google API的权限; - 静默登录的前提是用户设备上已经登录了Google账号,且之前授权过你的应用——如果是第一次使用,还是需要用户手动登录一次,但后续打开应用就可以自动获取信息了。
这个方案不仅符合API26+的权限规则,也是Google官方推荐的账号信息获取方式,安全且稳定。
内容的提问来源于stack exchange,提问作者Harshad Loya
相关产品推荐
相关产品推荐

