You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 19:07:33