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

Jetpack Compose Deeplink条件导航及登录校验问题求解决方案

Jetpack Compose 带登录校验的Deeplink条件导航解决方案

核心问题拆解

你的问题本质是Deeplink触发时绕过了登录校验逻辑,原因是系统通过onNewIntent/onResume直接传递导航指令,而没有经过全局的登录状态校验环节。下面给出针对性的落地方案,无需依赖复杂的多NavHost架构,用单NavHost配合全局状态监听即可解决。


解决方案实现

1. 统一导航入口,拦截所有Deeplink请求

不要让NavHost直接处理Deeplink,而是将所有导航请求(包括启动器启动、Deeplink跳转)统一路由到登录校验逻辑后再执行导航。

2. 用全局ViewModel监听登录状态

利用你已有的Application-ViewModel维护登录状态,在Activity中监听状态变化,联动导航逻辑。

3. 代码示例

全局登录状态ViewModel
class AppViewModel(application: Application) : AndroidViewModel(application) {
    private val _isLoggedIn = MutableStateFlow(false)
    val isLoggedIn = _isLoggedIn.asStateFlow()

    // 校验本地登录状态(比如从SharedPreferences读取)
    fun checkAuthStatus() {
        val prefs = application.getSharedPreferences("auth", Context.MODE_PRIVATE)
        _isLoggedIn.value = prefs.getBoolean("is_logged_in", false)
    }

    // 登录成功后更新状态
    fun markUserLoggedIn() {
        val prefs = application.getSharedPreferences("auth", Context.MODE_PRIVATE)
        prefs.edit().putBoolean("is_logged_in", true).apply()
        _isLoggedIn.value = true
    }
}
MainActivity导航逻辑处理
class MainActivity : ComponentActivity() {
    private lateinit var appViewModel: AppViewModel
    private var pendingDeepLink: Uri? = null // 保存待处理的Deeplink

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        appViewModel = ViewModelProvider(this)[AppViewModel::class.java]
        appViewModel.checkAuthStatus()
        handleIncomingIntent(intent) // 处理启动时的Intent

        setContent {
            MyAppTheme {
                val isLoggedIn by appViewModel.isLoggedIn.collectAsStateWithLifecycle()
                val navController = rememberNavController()

                // 监听登录状态+待处理Deeplink,触发导航
                LaunchedEffect(isLoggedIn, pendingDeepLink) {
                    when {
                        isLoggedIn -> {
                            pendingDeepLink?.let { uri ->
                                // 解析Deeplink为对应路由
                                val targetRoute = parseDeepLink(uri)
                                navController.navigate(targetRoute) {
                                    popUpTo(navController.graph.startDestinationId) { inclusive = true }
                                }
                                pendingDeepLink = null
                            } ?: navController.navigate(Screen.Home.route) {
                                popUpTo(navController.graph.startDestinationId) { inclusive = true }
                            }
                        }
                        else -> {
                            // 未登录时强制跳转到登录页
                            navController.navigate(Screen.Login.route) {
                                popUpTo(navController.graph.startDestinationId) { inclusive = true }
                            }
                        }
                    }
                }

                NavHost(navController = navController, startDestination = Screen.Splash.route) {
                    composable(Screen.Splash.route) {
                        // 闪屏页仅作为占位,实际导航由LaunchedEffect控制
                        SplashScreen()
                    }
                    composable(Screen.Login.route) {
                        LoginScreen(onLoginSuccess = {
                            appViewModel.markUserLoggedIn()
                        })
                    }
                    composable(Screen.Home.route) { HomeScreen() }
                    composable(Screen.PremiumContent.route) { PremiumContentScreen() }
                    // 其他需要登录的页面路由
                }
            }
        }
    }

    override fun onNewIntent(intent: Intent?) {
        super.onNewIntent(intent)
        intent?.let { handleIncomingIntent(it) }
    }

    // 处理所有传入的Intent,提取并保存Deeplink
    private fun handleIncomingIntent(intent: Intent) {
        if (intent.action == Intent.ACTION_VIEW && intent.data != null) {
            pendingDeepLink = intent.data
            appViewModel.checkAuthStatus() // 重新校验登录状态(防止用户已登出)
        }
    }

    // 根据你的Deeplink规则解析为路由
    private fun parseDeepLink(uri: Uri): String {
        return when (uri.path) {
            "/premium" -> Screen.PremiumContent.route
            else -> Screen.Home.route
        }
    }
}

// 路由定义
sealed class Screen(val route: String) {
    object Splash : Screen("splash")
    object Login : Screen("login")
    object Home : Screen("home")
    object PremiumContent : Screen("premium_content")
}

关键细节说明

  • pendingDeepLink缓存:将Deeplink请求暂存,等待登录状态校验完成后再执行导航,避免直接跳转绕过校验。
  • LaunchedEffect联动:通过监听登录状态和待处理Deeplink的变化,确保只有登录状态满足时才跳转到目标页面。
  • onNewIntent处理:覆盖该方法捕获后续的Deeplink请求,重复校验流程。

关于多NavHost的适用场景

多NavHost适合登录前后导航栈完全隔离的场景(比如登录后不需要回到登录页,且两个栈的路由完全独立)。如果只是需要前置登录校验,单NavHost配合状态监听足够简洁,无需引入额外复杂度。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 07:07:37