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

已登录Android应用使用Firebase Data Connect时随机出现「UNAUTHENTICATED: this operation requires a signed-in user」崩溃错误

已登录Android应用使用Firebase Data Connect时随机出现「UNAUTHENTICATED: this operation requires a signed-in user」崩溃错误

我太懂这种间歇性崩溃的糟心了——明明启动时已经确认用户登录了,结果时不时就蹦出这个认证错误,还完全摸不到规律。咱们一步步拆解问题,看看可能的诱因和解决办法:

可能的问题根源

  1. Auth令牌过期/刷新延迟:Firebase Auth的ID Token默认1小时过期,Data Connect请求需要有效令牌才能通过。虽然currentUser不为null,但令牌可能已失效,SDK自动刷新的空窗期刚好发起请求,就会触发错误。
  2. 协程作用域不规范:你在DataConnectRepository里用了自定义的CoroutineScope(Dispatchers.IO).launch,这种无绑定的作用域可能和Firebase Auth的上下文不同步,或者生命周期管理混乱,导致请求发起时认证状态没正确传递。
  3. Data Connect SDK潜在bug:你用的16.0.1版本可能存在令牌传递的间歇性问题,某些场景下自动生成的函数没正确获取最新的Auth令牌。
  4. App Check时机冲突:虽然是未强制模式,但App Check的令牌获取和Auth令牌的请求时机可能冲突,导致请求缺少必要的认证信息。

具体解决方案

一、手动绑定有效Auth令牌到Data Connect请求

自动生成的Data Connect函数偶尔会“漏拿”最新令牌,我们可以手动获取并附加,确保请求携带有效凭证:

// 修改DataConnectRepository的相关函数,改用suspend并手动处理令牌
object DataConnectRepository {
    private val connector: DefaultConnector = run {
        val instance = DefaultConnector.instance
        // 添加全局请求拦截器,给所有请求附加Auth令牌
        instance.dataConnect.intercept { request, next ->
            Firebase.auth.currentUser?.let { user ->
                // 获取缓存的有效令牌,false表示不强制刷新
                val idToken = user.getIdToken(false).await()
                val updatedRequest = request.newBuilder()
                    .addHeader("Authorization", "Bearer ${idToken.token}")
                    .build()
                next.proceed(updatedRequest)
            } ?: next.proceed(request)
        }
        instance
    }

    suspend fun updateSignInInfo(displayName: String?) {
        val currentUser = Firebase.auth.currentUser ?: return // 双重兜底检查
        try {
            connector.upsertUser.execute(displayName!!)
        } catch (e: Exception) {
            Log.i("User ID", currentUser.uid)
            Firebase.crashlytics.recordException(e)
            e.printStackTrace()
        }
    }
}

二、修复协程作用域问题

别再用自定义的CoroutineScope(Dispatchers.IO).launch,改用和应用生命周期绑定的作用域(比如lifecycleScope),避免上下文不同步:

// 在MyApp Composable中调用时,用lifecycleScope发起请求
@Composable
fun MyApp(
    lifecycleScope: LifecycleCoroutineScope,
    googleAuthUiClient: GoogleAuthUiClient,
    application: android.app.Application
) {
    // ... 其他代码
    val user = googleAuthUiClient.getSignedInUser()
    LaunchedEffect(user) {
        if (user != null) {
            DataConnectRepository.updateSignInInfo(user.username)
        }
    }
    // ... 其他代码
}

三、升级Firebase Data Connect SDK到最新稳定版

16.0.1版本可能存在令牌传递的间歇性bug,建议直接升级到最新稳定版——Firebase的更新日志里经常会修复这类认证相关的偶发问题。只需要在Module级别的build.gradle里更新依赖:

implementation 'com.google.firebase:firebase-dataconnect:最新稳定版号'

四、给认证错误添加重试机制

既然错误是间歇性的,我们可以在遇到UNAUTHENTICATED错误时自动重试一次(此时Auth令牌大概率已经刷新完成):

suspend fun updateSignInInfo(displayName: String?, retryCount: Int = 0) {
    val currentUser = Firebase.auth.currentUser ?: return
    try {
        connector.upsertUser.execute(displayName!!)
    } catch (e: Exception) {
        // 判断是否是gRPC的认证错误,且重试次数未达上限
        if (e is StatusException 
            && e.status.code == Status.Code.UNAUTHENTICATED 
            && retryCount < 1) {
            // 强制刷新Auth令牌后重试
            currentUser.getIdToken(true).await()
            updateSignInInfo(displayName, retryCount + 1)
        } else {
            Log.i("User ID", currentUser.uid)
            Firebase.crashlytics.recordException(e)
            e.printStackTrace()
        }
    }
}

五、调整App Check初始化顺序

虽然App Check是未强制模式,但可以让它在Auth状态初始化完成后再启动,避免令牌获取时机冲突:

// 修改MainActivity的onCreate方法
override fun onCreate(savedInstanceState: Bundle?) {
    enableEdgeToEdge()
    super.onCreate(savedInstanceState)
    FirebaseApp.initializeApp(this)
    
    // 先监听Auth状态,确保用户状态初始化完成后再初始化App Check和UI
    Firebase.auth.addAuthStateListener { auth ->
        if (BuildConfig.DEBUG) {
            Firebase.appCheck.installAppCheckProviderFactory(
                DebugAppCheckProviderFactory.getInstance(),
            )
        } else {
            Firebase.appCheck.installAppCheckProviderFactory(
                PlayIntegrityAppCheckProviderFactory.getInstance(),
            )
        }
        
        setContent {
            MyAppTheme {
                MyApp(
                    lifecycleScope = lifecycleScope,
                    googleAuthUiClient = googleAuthUiClient,
                    application = application
                )
            }
        }
    }
}

建议先从手动绑定令牌+修复协程作用域这两个方案入手,这是解决这类间歇性认证问题的最常见有效手段。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.08 12:17:58