已登录Android应用使用Firebase Data Connect时随机出现「UNAUTHENTICATED: this operation requires a signed-in user」崩溃错误
已登录Android应用使用Firebase Data Connect时随机出现「UNAUTHENTICATED: this operation requires a signed-in user」崩溃错误
我太懂这种间歇性崩溃的糟心了——明明启动时已经确认用户登录了,结果时不时就蹦出这个认证错误,还完全摸不到规律。咱们一步步拆解问题,看看可能的诱因和解决办法:
可能的问题根源
- Auth令牌过期/刷新延迟:Firebase Auth的ID Token默认1小时过期,Data Connect请求需要有效令牌才能通过。虽然
currentUser不为null,但令牌可能已失效,SDK自动刷新的空窗期刚好发起请求,就会触发错误。 - 协程作用域不规范:你在
DataConnectRepository里用了自定义的CoroutineScope(Dispatchers.IO).launch,这种无绑定的作用域可能和Firebase Auth的上下文不同步,或者生命周期管理混乱,导致请求发起时认证状态没正确传递。 - Data Connect SDK潜在bug:你用的16.0.1版本可能存在令牌传递的间歇性问题,某些场景下自动生成的函数没正确获取最新的Auth令牌。
- 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
相关产品推荐
相关产品推荐

