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

Compose Multiplatform实现Google登录遇生命周期错误及方案问询

Compose Multiplatform Google登录问题解决与优化方案

一、解决Android端注册时机错误问题

错误java.lang.IllegalStateException: LifecycleOwner ... is attempting to register while current state is RESUMED的核心原因是registerForActivityResult必须在Activity进入STARTED状态前完成注册,不能在点击事件等晚时机触发注册。结合expect/actual机制,调整方案如下:

1. 共享层定义expect接口

expect class GoogleAuthManager {
    suspend fun signIn(): GoogleSignInAccount?
}

// 共享层通用数据类,封装登录结果
data class GoogleSignInAccount(val serverAuthCode: String?)

2. Android端actual实现:提前注册Launcher

在Activity初始化阶段就完成ActivityResultLauncher的注册,而非点击时动态注册:

actual class GoogleAuthManager(private val activity: ComponentActivity) {
    private lateinit var signInLauncher: ActivityResultLauncher<Intent>
    private val signInResult = CompletableDeferred<GoogleSignInAccount?>()

    init {
        // 在类初始化时注册,确保早于Activity STARTED状态
        signInLauncher = activity.registerForActivityResult(
            ActivityResultContracts.StartActivityForResult()
        ) { result ->
            if (result.resultCode == Activity.RESULT_OK) {
                val task = GoogleSignIn.getSignedInAccountFromIntent(result.data)
                try {
                    val account = task.getResult(ApiException::class.java)
                    signInResult.complete(account?.let {
                        GoogleSignInAccount(it.serverAuthCode)
                    })
                } catch (e: ApiException) {
                    signInResult.complete(null)
                }
            } else {
                signInResult.complete(null)
            }
        }
    }

    actual suspend fun signIn(): GoogleSignInAccount? {
        val signInOptions = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
            .requestServerAuthCode("你的Web端客户端ID")
            .build()
        val signInIntent = GoogleSignIn.getClient(activity, signInOptions).signInIntent

        signInLauncher.launch(signInIntent)
        return signInResult.await()
    }
}

3. Activity中初始化Manager并传入Compose

class MainActivity : ComponentActivity() {
    private val googleAuthManager by lazy { GoogleAuthManager(this) }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            YourAppTheme {
                LoginScreen(googleAuthManager)
            }
        }
    }
}

4. Compose UI中调用登录

@Composable
fun LoginScreen(googleAuthManager: GoogleAuthManager) {
    var serverAuthCode by remember { mutableStateOf<String?>(null) }

    Button(
        onClick = {
            LaunchedEffect(Unit) {
                val account = googleAuthManager.signIn()
                serverAuthCode = account?.serverAuthCode
                // 后续处理serverAuthCode
            }
        }
    ) {
        Text("Google 登录")
    }
}

二、跨平台原生Google登录优化方案

如果不想用WebView,expect/actual是官方推荐的原生跨平台实现方式,可进一步优化架构:

1. 封装共享层Repository

将登录逻辑统一到共享层,隔离平台细节:

class AuthRepository(private val googleAuthManager: GoogleAuthManager) {
    suspend fun signInWithGoogle(): String? {
        val account = googleAuthManager.signIn()
        return account?.serverAuthCode
    }
}

2. iOS端actual实现

对应iOS原生GIDSignIn逻辑,获取serverAuthCode:

actual class GoogleAuthManager {
    actual suspend fun signIn(): GoogleSignInAccount? {
        return suspendCancellableCoroutine { cont ->
            val rootVC = UIApplication.shared.keyWindow?.rootViewController
            GIDSignIn.sharedInstance.signIn(withPresenting: rootVC) { result, error ->
                if (error != null || result?.user == null) {
                    cont.resume(null)
                    return@signIn
                }
                val serverAuthCode = result.user.serverAuthCode
                cont.resume(GoogleSignInAccount(serverAuthCode))
            }
        }
    }
}

3. 关键注意事项

  • Android端:确保GoogleAuthManager在Activity onCreate阶段初始化,避免Launcher注册时机过晚。
  • iOS端:需在Info.plist配置Google登录的URL Scheme(格式为com.googleusercontent.apps.你的客户端ID),并添加GoogleService-Info.plist文件。
  • 共享层仅暴露通用数据类和接口,平台实现细节完全隔离,便于维护。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 08:57:26