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

Credential Manager适配Family Link儿童账号登录失败问题咨询

使用Credential Manager实现Firebase Google登录时适配Family Link儿童账号的问题

实现代码

suspend fun signIn(): AuthResult? {
        val credentialManager = CredentialManager.create(context)
        val googleIdOption = GetGoogleIdOption.Builder()
            .setServerClientId(context.getString(R.string.server_client_id))
            .setFilterByAuthorizedAccounts(false)
            .setAutoSelectEnabled(true)
            .build()

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

        val result = try {
            val result = credentialManager.getCredential(context, request)
            val credential = result.credential
            val googleIdTokenCredential = GoogleIdTokenCredential
                .createFrom(credential.data)
            val googleIdToken = googleIdTokenCredential.idToken

            val firebaseCredential =
                GoogleAuthProvider.getCredential(googleIdToken, null)
            auth.signInWithCredential(firebaseCredential).await()
        } catch (e: Exception) {
            e.printStackTrace()
            Toast.makeText(context, e.message, Toast.LENGTH_SHORT).show()
            if (e is CancellationException) throw e
            null
        }
        return result
    }

问题描述

该登录流程对普通Google账号可正常工作,但在使用由家长通过Family Link管理的儿童账号登录时,会抛出如下错误:

androidx.credentials.exceptions.NoCredentialException: No credentials available
    at androidx.credentials.CredentialProviderFrameworkImpl.convertToJetpackGetException$credentials_release(CredentialProviderFrameworkImpl.kt:276)
    at androidx.credentials.CredentialProviderFrameworkImpl$onGetCredential$outcome$2.onError(CredentialProviderFrameworkImpl.kt:152)
    at androidx.credentials.CredentialProviderFrameworkImpl$onGetCredential$outcome$2.onError(CredentialProviderFrameworkImpl.kt:143)
    at android.credentials.CredentialManager$GetCredentialTransport.lambda$onError$2(CredentialManager.java:694)
    at android.credentials.CredentialManager$GetCredentialTransport.$r8$lambda$nlbYav9mLBoE6Yh1vFKCvITF3ks(Unknown Source:0)
    at android.credentials.CredentialManager$GetCredentialTransport$$ExternalSyntheticLambda2.run(Unknown Source:6)
    at androidx.credentials.CredentialManager$$ExternalSyntheticLambda0.execute(D8$$SyntheticClass:0)
    at android.credentials.CredentialManager$GetCredentialTransport.onError(CredentialManager.java:693)
    at android.credentials.IGetCredentialCallback$Stub.onTransact(IGetCredentialCallback.java:123)
    at android.os.Binder.execTransactInternal(Binder.java:1380)
    at android.os.Binder.execTransact(Binder.java:1311)

当前临时解决方案

当捕获到NoCredentialException时,调用reattemptSignInUsingLegacyGoogleSignIn()函数,使用已废弃的GoogleSignIn完成用户认证,该方案可正常适配Family Link儿童账号:

fun reattemptSignInUsingLegacyGoogleSignIn(): IntentSenderRequest {
        val gso = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
            .requestIdToken(context.getString(R.string.server_client_id))
            .requestEmail()
            .build();

        val mGoogleSignInClient = GoogleSignIn.getClient(context, gso);
        val signInIntent = mGoogleSignInClient.signInIntent

        val pendingIntent = PendingIntent.getActivity(
            context,
            0,
            signInIntent,
            PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
        )

        return IntentSenderRequest.Builder(pendingIntent).build()
    }

suspend fun getSignInResultFromIntent(intent: Intent): AuthResult? {
        val task = GoogleSignIn.getSignedInAccountFromIntent(intent)
        val result = try {
            val account = task.getResult(ApiException::class.java)
            val credential = GoogleAuthProvider.getCredential(account.idToken, null)
            auth.signInWithCredential(credential).await()
        } catch (e: ApiException) {
            Log.w("Auth", "Google sign in failed", e);
            Toast.makeText(context, e.toString(), Toast.LENGTH_LONG).show()
            null
        }
        return result
    }

由于Credential Manager是GoogleSignIn的官方替代方案,理论上应支持儿童账号登录,请问需要进行哪些特定配置或修改才能让Credential Manager适配Family Link管理的儿童账号?


解决方案

1. 升级Credential Manager依赖版本

早期版本的Credential Manager对儿童账号支持不完善,需确保使用最新稳定版依赖:

implementation "androidx.credentials:credentials:1.2.2"
implementation "androidx.credentials:credentials-play-services-auth:1.2.2"

2. 调整GetGoogleIdOption配置

儿童账号不支持自动选择功能,需关闭AutoSelect,强制弹出账号选择界面:

val googleIdOption = GetGoogleIdOption.Builder()
    .setServerClientId(context.getString(R.string.server_client_id))
    .setFilterByAuthorizedAccounts(false)
    .setAutoSelectEnabled(false) // 关闭自动选择
    .build()

3. 完善Google Cloud与Firebase配置

  • 在Google Cloud Console的OAuth同意屏幕中,确保配置了符合儿童隐私要求的政策(若应用面向13岁以下用户),并启用Google Identity API。
  • 验证OAuth客户端ID的包名、签名证书与应用完全匹配,儿童账号认证对客户端校验更严格。
  • 在Firebase控制台中,确认Google登录提供商已启用,且关联的OAuth客户端ID与Cloud Console中的一致。

4. 优化异常处理逻辑

避免捕获泛型Exception,针对性处理NoCredentialException,并重新发起带手动选择的请求:

val result = try {
    val result = credentialManager.getCredential(context, request)
    // 原有认证逻辑
    val credential = result.credential
    val googleIdTokenCredential = GoogleIdTokenCredential.createFrom(credential.data)
    val googleIdToken = googleIdTokenCredential.idToken
    val firebaseCredential = GoogleAuthProvider.getCredential(googleIdToken, null)
    auth.signInWithCredential(firebaseCredential).await()
} catch (e: NoCredentialException) {
    // 重新发起不带自动选择的请求
    val newGoogleIdOption = GetGoogleIdOption.Builder()
        .setServerClientId(context.getString(R.string.server_client_id))
        .setFilterByAuthorizedAccounts(false)
        .setAutoSelectEnabled(false)
        .build()
    val newRequest = GetCredentialRequest.Builder()
        .addCredentialOption(newGoogleIdOption)
        .build()
    val newResult = credentialManager.getCredential(context, newRequest)
    // 处理新请求结果
    val credential = newResult.credential
    val googleIdTokenCredential = GoogleIdTokenCredential.createFrom(credential.data)
    val googleIdToken = googleIdTokenCredential.idToken
    val firebaseCredential = GoogleAuthProvider.getCredential(googleIdToken, null)
    auth.signInWithCredential(firebaseCredential).await()
} catch (e: CancellationException) {
    throw e
} catch (e: Exception) {
    e.printStackTrace()
    Toast.makeText(context, e.message, Toast.LENGTH_SHORT).show()
    null
}

5. 确保设备系统版本支持

Credential Manager在Android 12(API 31)及以上版本正式引入,儿童账号的适配依赖系统层面支持,建议测试设备使用Android 12及以上系统。


内容的提问来源于stack exchange,提问作者user14678216

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 11:07:05