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

Android Google Credential Manager Kotlin API无网络时无限循环问题咨询

Google Credential Manager Kotlin API 无网络场景异常捕获问题解决

问题背景

使用Google Credential Manager Kotlin协程API实现Google登录时,正常场景下功能正常,但无网络环境中,getCredential方法不会抛出预期的IOException或其他可捕获异常,反而在后台持续输出[RequestTokenManager] getToken() -> NETWORK_ERROR日志,最终陷入无限循环导致UI无响应(ANR),所有捕获块均无法触发。目前临时改用Java API的getCredentialsAsync回调方案,但希望通过Kotlin API解决该问题。

可行解决方案

1. 提前检测网络状态

在调用getCredential前主动检查网络可用性,提前拦截无网络场景:

private fun isNetworkAvailable(context: Context): Boolean {
    val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
    val activeNetwork = connectivityManager.activeNetwork ?: return false
    val networkCapabilities = connectivityManager.getNetworkCapabilities(activeNetwork) ?: return false
    return networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) &&
           networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)
}

在登录方法中添加前置判断:

fun googlePravesh(context:Context, aadhikaarik:Boolean = true) {
    Log.e(TAG, "googlePravesh: ")
    viewModelScope.launch {
        if (!isNetworkAvailable(context)) {
            kimPragat.value = false
            Toast.makeText(context, "网络不可用,请检查网络设置", Toast.LENGTH_SHORT).show()
            return@launch
        }
        
        // 原有options、request构建逻辑...
        try {
            kimPragat.value = true
            val credential = CredentialManager.create(context).getCredential(context, request).credential
            // 后续凭证处理逻辑...
        } catch (_: NoCredentialException) {
            kimPragat.value = false
            googlePravesh(context,false)
        } catch(e: IOException) {
            Log.e(TAG, "googlePravesh: api exception", e)
            kimPragat.value = false
        } catch (e:Exception) {
            kimPragat.value = false
            Toast.makeText(context,e.message, Toast.LENGTH_SHORT).show()
        }
    }
}

2. 给协程添加超时机制

由于无网络时getCredential会无限重试,通过withTimeout强制终止调用,捕获超时异常来处理网络问题:

fun googlePravesh(context:Context, aadhikaarik:Boolean = true) {
    Log.e(TAG, "googlePravesh: ")
    viewModelScope.launch {
        val options = GetGoogleIdOption.Builder()
            .setFilterByAuthorizedAccounts(aadhikaarik)
            .setServerClientId("<server_id>")
            .setAutoSelectEnabled(true)
            .build()
        val request = GetCredentialRequest.Builder()
            .addCredentialOption(options)
            .build()
        try {
            kimPragat.value = true
            // 设置10秒超时,可根据需求调整
            val credential = withTimeout(10_000) {
                CredentialManager.create(context).getCredential(context, request).credential
            }
            // 后续凭证处理逻辑...
        } catch (e: TimeoutCancellationException) {
            // 超时大概率对应网络异常
            kimPragat.value = false
            Toast.makeText(context, "网络连接超时,请检查网络后重试", Toast.LENGTH_SHORT).show()
        } catch (_: NoCredentialException) {
            kimPragat.value = false
            googlePravesh(context,false)
        } catch(e: IOException) {
            Log.e(TAG, "googlePravesh: api exception", e)
            kimPragat.value = false
        } catch (e:Exception) {
            kimPragat.value = false
            Toast.makeText(context,e.message, Toast.LENGTH_SHORT).show()
        }
    }
}

3. 组合方案(推荐)

将提前网络检测与协程超时结合,既提前拦截大部分无网络场景,又能处理检测后网络突变的情况,彻底避免ANR风险。

4. 反馈官方Bug

此问题属于Google Credential Manager Kotlin API的异常行为(未按预期抛出网络异常),建议在Google官方Issue渠道提交反馈,复现步骤如下:

  • 环境:Android设备/模拟器,断开网络连接
  • 操作:调用CredentialManager.getCredential方法
  • 现象:后台输出NETWORK_ERROR日志,无异常抛出,协程挂起进入无限循环

临时方案说明

改用Java API的getCredentialsAsync回调机制,无网络时会正常触发onFailure回调,可作为过渡方案,但Kotlin API的上述方案更符合协程编程习惯。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.12 01:27:16