Android Google 登录迁移到Credential Manager

近期突然收到邮件说:您使用的是旧版 Google 登录 API,这种 API 已被弃用并计划于 2025 年移除。如需详细了解如何改而通过 Credential Manager 使用 Google 账号登录,请阅读我们的迁移指南。

然后就规划了更新但是因为别的相对紧急的需求就一直被搁置了,昨天老板突然过来说,他看到邮件说旧版Google 登录要废弃了,让我赶紧迁移,我说晚一点迁移也可以先做比较优先级高的需求,老板非常担忧说那废弃之后用户不都全登录不了怎么办!那就开始对接吧!

首先根据邮件内容来到 迁移介绍官方文档 ,看完一头雾水 不明所以,看到几个说迁移之后登录速度提升50%,而且使用更加简洁,旧版的登录回调确实不怎么优雅!

紧接着来到了重头戏 Google 登录 官方文档 仔细阅读了一下流程 并尝试编写代码:

dependencies {
  // ... other dependencies

  implementation "androidx.credentials:credentials:<latest version>"
  implementation "androidx.credentials:credentials-play-services-auth:<latest version>"
  implementation "com.google.android.libraries.identity.googleid:googleid:<latest version>"
}
  • 编写登录代码
  1. 首先创建一个CredentialManager
credentialManager = CredentialManager
    .create(context)
  1. 然后再构建一个 GetSignInWithGoogleOption 登录项
val signInWithGoogleOption: GetSignInWithGoogleOption = GetSignInWithGoogleOption.Builder()
  .setServerClientId(WEB_CLIENT_ID)
  .setNonce(<nonce string to use when generating a Google ID token>)
  .build()
  1. 触发登录操作
val request: GetCredentialRequest = GetCredentialRequest
    .Builder()
    .addCredentialOption(googleIdOption)
    .build()

credentialManager.getCredentialAsync(
    it,
    request,
    CancellationSignal(),
    Executors.newSingleThreadExecutor(),
    object : CredentialManagerCallback<GetCredentialResponse, GetCredentialException> {
        override fun onError(e: GetCredentialException) {
            googleCallBack?.onFailure(e)
        }

        override fun onResult(result: GetCredentialResponse) {
            createGoogleIdToken(result.credential, googleCallBack)
        }

    })
  1. 获取登录信息 在登录成功之后会回调onResult 方法可以拿到GetCredentialResponse 此时可以通过 GoogleIdTokenCredential.createFrom 来获取用户信息
val credentialData = result.data
val googleIdTokenCredential = GoogleIdTokenCredential.createFrom(credentialData)
  1. 退出登录操作
val clearCredentialRequest = ClearCredentialStateRequest()
credentialManager.clearCredentialStateAsync(
    clearCredentialRequest,
    CancellationSignal(),
    Executors.newSingleThreadExecutor(),
    object : CredentialManagerCallback<Void?, ClearCredentialException> {
        override fun onError(e: ClearCredentialException) {

        }

        override fun onResult(result: Void?) {

        }

    })
  • 完整代码
package com.chic.point.widget.utlis

import android.content.Context
import android.os.CancellationSignal
import androidx.credentials.ClearCredentialStateRequest
import androidx.credentials.Credential
import androidx.credentials.CredentialManager
import androidx.credentials.CredentialManagerCallback
import androidx.credentials.CustomCredential
import androidx.credentials.GetCredentialRequest
import androidx.credentials.GetCredentialResponse
import androidx.credentials.exceptions.ClearCredentialException
import androidx.credentials.exceptions.GetCredentialException
import com.google.android.libraries.identity.googleid.GetSignInWithGoogleOption
import com.google.android.libraries.identity.googleid.GoogleIdTokenCredential
import java.lang.ref.WeakReference
import java.util.concurrent.Executors


/**
 * @date   : 2025/2/26
 * @author spc
 * @Description:
 */
object GoogleSignInManager {

    private lateinit var credentialManager: CredentialManager

    private fun initCredentialManager(context: Context) {
        if (::credentialManager.isInitialized.not()) {
            credentialManager = CredentialManager
                .create(context)
        }
    }

    fun googleSignIn(
        context: Context,
        apiKey: String,
        googleCallBack: GoogleCallBack? = null,
    ) {
        val weakContext = WeakReference(context.applicationContext)
        weakContext.get()?.let {
            initCredentialManager(it)
            val googleIdOption: GetSignInWithGoogleOption = GetSignInWithGoogleOption
                .Builder(apiKey)
                .build()

            val request: GetCredentialRequest = GetCredentialRequest
                .Builder()
                .addCredentialOption(googleIdOption)
                .build()

            credentialManager.getCredentialAsync(
                it,
                request,
                CancellationSignal(),
                Executors.newSingleThreadExecutor(),
                object : CredentialManagerCallback<GetCredentialResponse, GetCredentialException> {
                    override fun onError(e: GetCredentialException) {
                        googleCallBack?.onFailure(e)
                    }

                    override fun onResult(result: GetCredentialResponse) {
                        createGoogleIdToken(result.credential, googleCallBack)
                    }

                })
        }

    }

    private fun createGoogleIdToken(
        credential: Credential?,
        googleCallBack: GoogleCallBack? = null,
    ) {
        // Check if credential is of type Google ID
        if (credential != null && credential is CustomCredential && credential.type == GoogleIdTokenCredential.TYPE_GOOGLE_ID_TOKEN_CREDENTIAL) {
            // Create Google ID Token
            val credentialData = credential.data
            val googleIdTokenCredential = GoogleIdTokenCredential.createFrom(credentialData)
            googleCallBack?.onSuccess(googleIdTokenCredential)
        } else {
            googleCallBack?.onFailure(null)
        }
    }

    /**
     * to log out
     */
    fun logOut(context: Context) {
        val weakContext = WeakReference(context.applicationContext)
        weakContext.get()?.let {
            initCredentialManager(it)
            val clearCredentialRequest = ClearCredentialStateRequest()
            credentialManager.clearCredentialStateAsync(
                clearCredentialRequest,
                CancellationSignal(),
                Executors.newSingleThreadExecutor(),
                object : CredentialManagerCallback<Void?, ClearCredentialException> {
                    override fun onError(e: ClearCredentialException) {

                    }

                    override fun onResult(result: Void?) {

                    }

                })
        }
    }
}