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

rememberLauncherForActivityResult的onResult未触发问题排查

Google一键登录:rememberLauncherForActivityResult的onResult回调未触发,但onActivityResult正常工作

问题描述

实现Google一键登录时,rememberLauncherForActivityResult的onResult回调始终无法触发,但重写宿主Activity的onActivityResult方法可以正常接收登录结果。设置noHistory标志也未产生任何效果。

启动Launcher的代码:

var authStarted by remember {
    mutableStateOf(true)
}

val activity = LocalContext.current.findActivity()
val launcher = rememberLauncherForActivityResult(
    contract = GoogleSignInContract(),
    onResult = { it ->
        if (it == null) return@rememberLauncherForActivityResult
        it.addOnSuccessListener {
            if (it.idToken == null) return@addOnSuccessListener
            FBAuth.firebaseAuthWithGoogle(activity, it.idToken!!)
        }
    })
if (authStarted) {
    SideEffect {
        launcher.launch(AUTH_CODE)
        authStarted = false
    }
}

自定义Contract代码:

class GoogleSignInContract : ActivityResultContract<Int, Task<GoogleSignInAccount>?>() {
    override fun createIntent(context: Context, input: Int): Intent {
        val client =
            GoogleSignIn.getClient(context, FBAuth.newGsi(context.getString(R.string.web_oauth)))
        return client.signInIntent
    }

    override fun parseResult(resultCode: Int, intent: Intent?): Task<GoogleSignInAccount>? {
        Log.d("GoogleSignInContract", "Result code: $resultCode")
        return when (resultCode) {
            Activity.RESULT_OK -> {
                GoogleSignIn.getSignedInAccountFromIntent(intent)
            }

            else -> {
                null
            }
        }
    }
}

解决方案

  • 检查宿主Activity的onActivityResult实现
    如果宿主Activity重写了onActivityResult方法,必须确保调用了super.onActivityResult(requestCode, resultCode, data)——否则Jetpack Compose的ActivityResultLauncher无法接收结果回调,这是最常见的原因。

  • 替换自定义Contract为官方实现
    自定义ActivityResultContract容易引入潜在问题,直接使用官方的ActivityResultContracts.StartActivityForResult()可以简化逻辑并避免回调丢失:

    val launcher = rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
        if (result.resultCode == Activity.RESULT_OK) {
            val signInTask = GoogleSignIn.getSignedInAccountFromIntent(result.data)
            signInTask.addOnSuccessListener { account ->
                account.idToken?.let { token ->
                    FBAuth.firebaseAuthWithGoogle(activity, token)
                }
            }
            signInTask.addOnFailureListener {
                // 处理登录失败场景,比如用户取消登录
            }
        }
    }
    
    // 启动登录流程
    LaunchedEffect(Unit) {
        val signInClient = GoogleSignIn.getClient(activity, FBAuth.newGsi(activity.getString(R.string.web_oauth)))
        launcher.launch(signInClient.signInIntent)
    }
    
  • 改用LaunchedEffect替代SideEffect
    SideEffect会在每次重组时执行,虽然你设置了authStarted = false,但LaunchedEffect(Unit)更适合执行一次性的启动操作,确保Launcher只被调用一次,避免因重组导致的异常。

  • 检查Activity启动模式
    避免为宿主Activity设置singleInstance或singleTask启动模式,这类模式会改变Activity栈的行为,导致结果无法正确回调到Compose的Launcher。保持默认的standard启动模式即可。

  • 验证上下文获取的正确性
    可以直接使用LocalActivity.current(需导入androidx.activity.compose.LocalActivity)替代自定义的findActivity()方法,确保Launcher绑定到当前正确的宿主Activity,避免因上下文错误导致的回调丢失。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 15:53:14