如何通过Credential Manager检查Google登录状态并获取用户邮箱
解决方案
要实现应用重启后自动检查已登录状态并获取用户邮箱,你需要在应用启动时主动调用CredentialManager的凭据获取接口,同时调整配置让它优先返回已授权的账户。具体步骤如下:
1. 添加启动时的自动登录检查逻辑
在onCreate方法中,初始化CredentialManager后,直接添加自动检查登录的协程逻辑,无需等待用户点击登录按钮。
2. 调整GetGoogleIdOption配置
- 设置
setFilterByAuthorizedAccounts(true):只返回当前应用已授权过的Google账户凭据 - 保持
setAutoSelectEnabled(true):让CredentialManager自动返回匹配的凭据,无需用户手动选择
3. 完整修改后的代码
class MainActivity : AppCompatActivity() { private lateinit var googleIdOption: GetGoogleIdOption private lateinit var loginBtn: Button private lateinit var textView: TextView private lateinit var logoutBtn: Button override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) enableEdgeToEdge() setContentView(R.layout.activity_main) ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets -> val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars()) v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom) insets } loginBtn = findViewById(R.id.btn) textView = findViewById(R.id.textview) logoutBtn = findViewById(R.id.logout) val credentialManager = CredentialManager.create(this) // 应用启动时自动检查已登录状态 lifecycleScope.launch { checkSavedCredentials(credentialManager) } logoutBtn.setOnClickListener { lifecycleScope.launch { userPreferencesDataStore.edit { it.clear() } val request = ClearCredentialStateRequest() credentialManager.clearCredentialState(request) // 登出后更新UI,回到登录状态提示 textView.text = "已登出,请重新登录" } } loginBtn.setOnClickListener { performLogin(credentialManager) } } private suspend fun checkSavedCredentials(credentialManager: CredentialManager) { try { val rawNonce = UUID.randomUUID().toString() val bytes = rawNonce.toByteArray() val md = MessageDigest.getInstance("SHA-256") val digest = md.digest(bytes) val hashedNonce = digest.fold("") { str, it -> str + "%02x".format(it) } googleIdOption = GetGoogleIdOption.Builder() .setFilterByAuthorizedAccounts(true) // 关键:只返回已授权账户 .setServerClientId("myapikey.apps.googleusercontent.com") .setAutoSelectEnabled(true) // 自动选择匹配的凭据 .setNonce(hashedNonce) .build() val request: GetCredentialRequest = GetCredentialRequest.Builder() .addCredentialOption(googleIdOption) .build() val result = credentialManager.getCredential( request = request, context = this@MainActivity, ) handleSignIn(result) } catch (e: GetCredentialException) { // 没有已保存的凭据,停留在登录状态 Log.e("LoginCheck", "No saved credentials found", e) textView.text = "请点击登录" } } private fun performLogin(credentialManager: CredentialManager) { lifecycleScope.launch { try { val rawNonce = UUID.randomUUID().toString() val bytes = rawNonce.toByteArray() val md = MessageDigest.getInstance("SHA-256") val digest = md.digest(bytes) val hashedNonce = digest.fold("") { str, it -> str + "%02x".format(it) } googleIdOption = GetGoogleIdOption.Builder() .setFilterByAuthorizedAccounts(false) // 登录时允许选择所有账户 .setServerClientId("myapikey.apps.googleusercontent.com") .setAutoSelectEnabled(true) .setNonce(hashedNonce) .build() val request: GetCredentialRequest = GetCredentialRequest.Builder() .addCredentialOption(googleIdOption) .build() val result = credentialManager.getCredential( request = request, context = this@MainActivity, ) handleSignIn(result) } catch (e: GetCredentialException) { Log.e("Erroris", "Error getting credential", e) } } } private fun handleSignIn(result: GetCredentialResponse) { // Handle the successfully returned credential. when (val credential = result.credential) { is PublicKeyCredential -> { val responseJson = credential.authenticationResponseJson } is PasswordCredential -> { val username = credential.id val password = credential.password } is CustomCredential -> { if (credential.type == GoogleIdTokenCredential.TYPE_GOOGLE_ID_TOKEN_CREDENTIAL) { try { val googleIdTokenCredential = GoogleIdTokenCredential.createFrom(credential.data) val googleIdToken = googleIdTokenCredential.idToken Log.i("answer", googleIdToken) val userEmail = googleIdTokenCredential.id // 这里就是用户邮箱 Log.i("answer", userEmail) val displayName = googleIdTokenCredential.displayName Log.i("answer", displayName.toString()) val personPhoto = googleIdTokenCredential.profilePictureUri Log.i("answer", personPhoto.toString()) // 更新UI显示已登录状态 textView.text = "当前登录用户:$userEmail" } catch (e: GoogleIdTokenParsingException) { Log.e("Erroris", "Received an invalid google id token response", e) } } else { Log.e("Erroris", "Unexpected type of credential") } } else -> { Log.e("Erroris", "Unexpected type of credential") } } } }
关键说明
- 自动检查逻辑:在
onCreate中调用checkSavedCredentials,应用启动后立即尝试获取已保存的凭据 - 过滤已授权账户:
setFilterByAuthorizedAccounts(true)确保只返回当前应用登录过的账户,避免弹出账户选择框 - 异常处理:如果没有已保存凭据(比如用户首次打开或已登出),会进入异常分支,保持登录状态提示
- 登录与检查的配置差异:登录时
setFilterByAuthorizedAccounts(false)允许用户选择新账户,自动检查时设为true只找已授权账户
内容的提问来源于stack exchange,提问作者BraveEvidence
相关产品推荐
相关产品推荐

