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

GoogleIdTokenCredential.getId()返回整数而非字符串问题求助

GoogleIdTokenCredential返回整数ID且displayName为null的异常排查与解决

我在基于GoogleIdTokenCredential构建登录系统时遇到异常:

  • 部分场景下googleIdTokenCredential.id返回整数类型值,而非官方文档承诺的非空邮箱字符串
  • 同时googleIdTokenCredential.displayName返回null

依赖配置和核心代码如下:

依赖配置(build.gradle)

dependencies {
     // dependencies for credential
    implementation("androidx.credentials:credentials-play-services-auth:1.2.2")
    implementation("com.google.android.libraries.identity.googleid:1.1.1")
}

Fragment核心代码

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)

    val googleIdOption by lazy {
        GetGoogleIdOption.Builder().setFilterByAuthorizedAccounts(false)
            .setServerClientId(serverClientId)
            .setAutoSelectEnabled(true).setNonce(generateNonce()).build()
    }

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

    val mContext = requireContext()
    val credentialManager by lazy { androidx.credentials.CredentialManager.create(mContext) }

    lifecycleScope.launch {
        try {
            val result = credentialManager.getCredential(
                request = request,
                context = mContext,
            )
            handleSignIn(result)
        } catch (e: androidx.credentials.exceptions.GetCredentialException) {
            showMessage("Failed to get credential: $e")
        }
    }
}

private fun handleSignIn(result: androidx.credentials.GetCredentialResponse) {
    when (val credential = result.credential) {
        is CustomCredential -> {
            if (credential.type == GoogleIdTokenCredential.TYPE_GOOGLE_ID_TOKEN_CREDENTIAL) {
                try {
                    val googleIdTokenCredential =
                        GoogleIdTokenCredential.createFrom(credential.data)

                    val id = googleIdTokenCredential.id
                    val displayName = googleIdTokenCredential.displayName

                    if (displayName == null) {
                        showMessage("Login Failed\nid: $id")
                        return
                    }

                } catch (e: GoogleIdTokenParsingException) {
                    showMessage("Received an invalid google id token response, $e")
                }
            }
        }

        else -> {
            showMessage("Unexpected type of credential")
        }
    }
}

private fun generateNonce(): String {
    val nonceBytes = ByteArray(16)
    SecureRandom().nextBytes(nonceBytes)
    return Base64.encodeToString(
        nonceBytes, Base64.NO_PADDING or Base64.NO_WRAP or Base64.URL_SAFE
    )
}

private fun showMessage(message: String) {
    Toast.makeText(requireContext(), message, Toast.LENGTH_SHORT).show()
}

排查与解决思路

1. 显式添加必要的OAuth Scopes

官方文档中,若要获取邮箱(即id字段)和用户显示名称,需要确保请求包含email和profile scope。默认情况下GetGoogleIdOption会包含这些scope,但显式指定可以避免潜在的配置遗漏:

val googleIdOption by lazy {
    GetGoogleIdOption.Builder()
        .setFilterByAuthorizedAccounts(false)
        .setServerClientId(serverClientId)
        .setAutoSelectEnabled(true)
        .setNonce(generateNonce())
        // 显式声明需要的权限范围
        .setScopes(listOf("email", "profile"))
        .build()
}

缺失email scope是导致返回整数ID(用户的Google ID而非邮箱)的核心原因。

2. 验证Server Client ID的正确性

确保serverClientId是Google Cloud Console中创建的Web应用类型OAuth 2.0客户端ID,而非Android应用的客户端ID。错误的客户端ID会导致返回数据字段不完整。

3. 检查原始Credential数据

直接打印credential.data的完整内容,确认Google Play Services返回的原始数据是否异常:

Log.d("GoogleCredentialDebug", "Raw credential data: ${credential.data}")

如果原始数据中的id本身就是整数,说明是服务端或Play Services的返回问题,需进一步排查设备的Google Play Services版本。

4. 强制检查Google Play Services版本

设备上的Google Play Services版本过低可能导致API行为异常,添加版本检查:

val status = GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(requireContext())
if (status != ConnectionResult.SUCCESS) {
    showMessage("请更新Google Play Services")
    return
}

5. 调整Credential Manager初始化方式

避免使用lazy初始化credentialManager,改为在onViewCreated中直接初始化,规避生命周期相关的潜在问题:

val credentialManager = androidx.credentials.CredentialManager.create(mContext)

内容的提问来源于stack exchange,提问作者AR Sharif Uddin JUMMAN

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 23:32:02