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

Firebase SignInClient遇ApiException:8及模拟器功能缺失问题求助

Google一键登录异常:ApiException:8 与 Missing Feature 错误排查

问题现象

点击谷歌邮箱授权图标按钮时出现以下异常:

  • OnePlus 7T真机:抛出ApiException:8
  • 模拟器:提示Missing Feature{name=auth_api_credentials_begin_sign_in, version=8}

已尝试的无效方案

  • 清理应用缓存
  • 重新放置google-services.json文件到应用包内
  • 修正SHA1和SHA256签名值为正确值
  • 确认真机谷歌服务已授权
  • 验证Web Client ID正确无误
  • 梳理并优化代码逻辑
  • 新建项目导入现有代码重试

相关代码

ViewModel依赖注入字段

@GmailSignIn private val signIn: BeginSignInRequest,
@GmailSignUp private val signUp: BeginSignInRequest

// 注:上述变量来自ViewModel构造函数,用于处理授权逻辑:已有授权账号则登录,否则注册

Hilt提供的请求实例

@Provides
@GmailSignIn
fun provideSignInRequest() = BeginSignInRequest.builder()
    .setGoogleIdTokenRequestOptions(
        BeginSignInRequest.GoogleIdTokenRequestOptions.builder()
            .setSupported(true)
            .setServerClientId(ServerClient)
            .setFilterByAuthorizedAccounts(true)
            .build()
    )
    .setAutoSelectEnabled(true)
    .build()

@Provides
@GmailSignUp
fun provideSignUpRequest() = BeginSignInRequest.builder()
    .setGoogleIdTokenRequestOptions(
        BeginSignInRequest.GoogleIdTokenRequestOptions.builder()
            .setSupported(true)
            .setServerClientId(ServerClient)
            .setFilterByAuthorizedAccounts(false)
            .build()
    )
    .build()

// 注:使用Hilt实现注解的依赖注入

自定义Qualifier注解

@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class GmailSignIn

@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class GmailSignUp

ViewModel中的登录与授权逻辑

// 注:该函数用于向其他页面传递Gmail登录数据
suspend fun gmailOneTapClient(): IntentSender {
    val signInResult = oneTapClient.beginSignIn(signIn).await()
              stateAuthWithGmail.emit(
                  AuthSignInResult(
                      successful = oneTapClient.beginSignIn(signIn).await(),
                      errorMessage = null,
                      Loading = false
                  )
              )
              if(signInResult == null){
                  oneTapClient.beginSignIn(signUp).await()
                 stateAuthWithGmail.emit(
                      AuthSignInResult(
                          successful = oneTapClient.beginSignIn(signUp).await(),
                          errorMessage = null,
                          Loading = false
                      )
                  )
              }
     return signInResult.pendingIntent.intentSender
}

// 注:该函数处理Gmail授权逻辑
fun gmailAuth(credential: AuthCredential){
        viewModelScope.launch(Dispatchers.IO){
            stateAuthWithGmail.emit(
                AuthSignInResult(
                    errorMessage = null,
                    Loading = true
                )
            )
                when(val result = authorizationRepository.gmailAuth(credential)){
                is GmailAuthorizationEvent.Error ->{
                    stateAuthWithGmail.emit(
                        AuthSignInResult(
                            errorMessage = result.errorMessage,
                            successful = null
                        )
                    )
                }
                    is GmailAuthorizationEvent.Success ->{
                        stateAuthWithGmail.emit(
                            AuthSignInResult(
                                errorMessage = null,
                                Loading = false,
                                successful = result.data
                            )
                        )
                    }
                    is GmailAuthorizationEvent.Loading ->{
                        stateAuthWithGmail.emit(
                            AuthSignInResult(
                                errorMessage = null,
                                successful = null,
                                Loading = true
                            )
                        )
                    }
                }
        }
    }

登录结果处理Launcher

// 注:该Launcher用于在其他页面获取IntentSender数据,导航组件配置无误
val launcherGmailSignIn = rememberLauncherForActivityResult(
        contract = ActivityResultContracts.StartIntentSenderForResult()
    ){ activityResult ->
        if(activityResult.resultCode == Activity.RESULT_OK){
            try {
                val credentials = oneTapClient.getSignInCredentialFromIntent(
                    activityResult.data
                )
                val googleIdToken = credentials.googleIdToken
                val googleCred = GoogleAuthProvider.getCredential(googleIdToken,null)
            authorizationViewModel.gmailAuth(googleCred)
            }catch (e:ApiException){
               print(e)
            }
        }
    }

登录触发与导航逻辑

// 注:该逻辑用于跳转并获取用户数据到其他页面
navigateToGoogleSignIn = {
                    navigationScope.launch(Dispatchers.Main){
                      launcherGmailSignIn.launch(
                            IntentSenderRequest.Builder(
                                authorizationViewModel.gmailOneTapClient()
                            ).build()
                        )
                        navController.navigate("news_screen")
                    }
                }

排查与解决建议

1. 升级Google Play服务版本

Missing Feature错误核心原因是设备/模拟器的Google Play服务版本过低,不支持BeginSignInRequest要求的API版本(version=8):

  • 真机:打开Google Play商店,搜索「Google Play服务」并更新到最新版本
  • 模拟器:创建AVD时选择Android 12及以上的系统镜像(确保包含Google Play服务),或在模拟器内手动更新Google Play服务

2. 修复gmailOneTapClient的逻辑问题

原代码存在重复调用beginSignIn、空值处理错误的问题,会导致重复请求触发限制,修改如下:

suspend fun gmailOneTapClient(): IntentSender {
    val signInResult = try {
        // 先尝试登录已有授权账号
        oneTapClient.beginSignIn(signIn).await()
    } catch (e: ApiException) {
        // 登录失败(无授权账号),切换到注册流程
        oneTapClient.beginSignIn(signUp).await()
    }
    // 仅发送一次正确的状态
    stateAuthWithGmail.emit(
        AuthSignInResult(
            successful = signInResult,
            errorMessage = null,
            Loading = false
        )
    )
    return signInResult.pendingIntent.intentSender
}

3. 验证OAuth客户端配置

  • 登录Google Cloud控制台,确认Android客户端和Web客户端的SHA1/SHA256签名均已正确配置(与本地签名文件一致)
  • 检查ServerClient是否为Web客户端的Client ID,而非Android客户端ID
  • 确保OAuth同意屏幕已完成配置,测试阶段需添加测试用户邮箱

4. 处理ApiException:8的场景

ApiException:8对应CommonStatusCodes.INTERNAL_ERROR,常见解决方向:

  • 确保设备网络正常,可访问Google服务
  • 避免在非主线程处理UI相关的登录请求(协程调度器使用Dispatchers.Main或合适的调度器)
  • 清理设备上已保存的Google账号授权记录,重新授权

5. 优化导航逻辑

原代码在启动登录流程后立即跳转页面,会导致登录结果无法正确接收,需改为登录成功后再导航:

// 在ViewModel的gmailAuth函数中,成功分支添加导航逻辑
is GmailAuthorizationEvent.Success -> {
    stateAuthWithGmail.emit(
        AuthSignInResult(
            errorMessage = null,
            Loading = false,
            successful = result.data
        )
    )
    // 触发导航事件,让UI层处理跳转
    _navigateToNewsScreen.emit(Unit)
}

// UI层监听导航事件
LaunchedEffect(authorizationViewModel.navigateToNewsScreen) {
    authorizationViewModel.navigateToNewsScreen.collect {
        navController.navigate("news_screen")
    }
}

// 修改登录触发逻辑,移除立即跳转
navigateToGoogleSignIn = {
    navigationScope.launch(Dispatchers.Main) {
        launcherGmailSignIn.launch(
            IntentSenderRequest.Builder(
                authorizationViewModel.gmailOneTapClient()
            ).build()
        )
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 04:10:08