Android API 26及以上版本如何获取用户账户名?
解决Android 8.0+获取用户账户名的问题
我完全懂你现在的头疼——Android 8.0(API26)之后AccountManager的权限卡得特别严,老方法全失效了。下面我给你一步步拆解能跑通的实现逻辑:
核心规则先明确
在Android 8.0及以上版本,应用只能访问两类账户:自身身份验证器创建的账户,或者用户手动授予访问权限的第三方账户。直接调用
getAccounts()这类方法大概率返回空,必须走授权流程。
具体实现步骤
1. 先搞定基础权限
首先在AndroidManifest.xml里声明权限:
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
Android 6.0(API23)及以上还要动态申请这个权限:
private const val REQUEST_CODE_ACCOUNTS = 1001 // 检查并请求权限 if (ContextCompat.checkSelfPermission(this, Manifest.permission.GET_ACCOUNTS) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions( this, arrayOf(Manifest.permission.GET_ACCOUNTS), REQUEST_CODE_ACCOUNTS ) } else { // 权限就绪,开始获取账户 fetchTargetAccounts() } // 处理权限申请结果 override fun onRequestPermissionsResult( requestCode: Int, permissions: Array<out String>, grantResults: IntArray ) { super.onRequestPermissionsResult(requestCode, permissions, grantResults) if (requestCode == REQUEST_CODE_ACCOUNTS && grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) { fetchTargetAccounts() } }
2. 确定目标账户类型
你得明确要拿哪种账户的信息——比如Google账户的类型是com.google,小米账户是com.xiaomi,不同厂商/服务的账户类型不一样。下面以Google账户为例演示代码。
3. 尝试获取+触发授权
如果直接调用getAccountsByType()返回空,就需要引导用户授权访问该类型账户:
private fun fetchTargetAccounts() { val accountManager = AccountManager.get(this) val targetAccountType = "com.google" // 替换成你需要的账户类型 val existingAccounts = accountManager.getAccountsByType(targetAccountType) if (existingAccounts.isNotEmpty()) { // 已有可访问的账户,直接拿账户名 existingAccounts.forEach { account -> Log.d("AccountInfo", "获取到账户名:${account.name}") // 这里就可以把account.name塞进邮件里了 } } else { // 无可用账户,请求用户授权 // 这里的scope对应获取邮箱的权限,不同需求换不同scope val authScope = "oauth2:https://www.googleapis.com/auth/userinfo.email" accountManager.getAuthToken( Account(null, targetAccountType), authScope, null, this, AccountManagerCallback<Bundle> { future -> try { val resultBundle = future.result val authToken = resultBundle.getString(AccountManager.KEY_AUTHTOKEN) if (authToken != null) { // 授权成功,再次拉取账户列表 val authorizedAccounts = accountManager.getAccountsByType(targetAccountType) authorizedAccounts.forEach { account -> Log.d("AccountInfo", "授权后获取到账户名:${account.name}") // 执行发送邮件的逻辑 } } } catch (e: Exception) { e.printStackTrace() // 处理授权失败的情况,比如用户点了拒绝 } }, null ) } }
几个关键提醒
- 必须指定账户类型:API26之后不能批量获取所有账户,必须精准指定
accountType,否则返回空列表。 - Scope要匹配需求:不同账户类型需要对应的权限范围,比如Google账户要拿用户名就用
userinfo.profile,拿邮箱用userinfo.email。 - 授权绕不开:系统会弹出标准的授权弹窗,用户必须同意才能拿到信息——这是Android的隐私保护机制,没有捷径可走。
内容的提问来源于stack exchange,提问作者adamb
相关产品推荐
相关产品推荐

