跳转到正文
YGJoon 技术博客

Android Kotlin Compose 导航与深链

发布于:
·801 字 · 约 2 分钟·作者:
Compose Navigation 路由设计与深链打通:参数传递、多返回栈 BottomBar、Manifest 跳转配置,多模块下导航图的拆分策略。
Android Kotlin Compose 导航与深链文章封面
目录

路由设计

sealed class Destinations(val route: String) {
    data object Home : Destinations("home")
    data object Detail : Destinations("detail/{id}") {
        fun createRoute(id: Long) = "detail/$id"
    }
}

基础导航

@Composable
fun AppNavGraph(navController: NavHostController = rememberNavController()) {
    NavHost(navController, startDestination = Destinations.Home.route) {
        composable(Destinations.Home.route) {
            HomeRoute(onOpenDetail = { id ->
                navController.navigate(Destinations.Detail.createRoute(id))
            })
        }
        composable(
            Destinations.Detail.route,
            arguments = listOf(navArgument("id") { type = NavType.LongType })
        ) { entry ->
            val id = entry.arguments?.getLong("id") ?: return@composable
            DetailRoute(id)
        }
    }
}

多返回栈与 BottomBar

val tabs = listOf("feed", "search", "profile")
val navController = rememberNavController()

NavigationBar {
    tabs.forEach { tab ->
        NavigationBarItem(
            selected = navController.currentDestination?.route == tab,
            onClick = {
                navController.navigate(tab) {
                    popUpTo(navController.graph.startDestinationId) { saveState = true }
                    launchSingleTop = true
                    restoreState = true
                }
            },
            icon = { Icon(Icons.Default.Home, null) },
            label = { Text(tab) }
        )
    }
}

深链与外部跳转

Manifest 配置

<activity
    android:name=".MainActivity"
    android:exported="true">
    <intent-filter>
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
        <data android:scheme="app" android:host="example" android:pathPrefix="/detail" />
    </intent-filter>
</activity>

Compose 处理

@Composable
fun MainApp(navController: NavHostController = rememberNavController()) {
    val intent = LocalContext.current.findActivity()?.intent
    LaunchedEffect(intent) {
        intent?.data?.lastPathSegment?.toLongOrNull()?.let { id ->
            navController.navigate(Destinations.Detail.createRoute(id))
        }
    }
    AppNavGraph(navController)
}

多模块导航

interface NavigationDestination {
    val route: String
    fun register(navGraphBuilder: NavGraphBuilder, navController: NavController)
}

class ProfileDestination @Inject constructor(): NavigationDestination {
    override val route = "profile"
    override fun register(navGraphBuilder: NavGraphBuilder, navController: NavController) {
        navGraphBuilder.composable(route) { ProfileRoute() }
    }
}

内存与状态保存

navController.currentBackStackEntry?.savedStateHandle?.set("result", result)
navController.popBackStack()

val result = navController.currentBackStackEntry?.savedStateHandle?.getStateFlow("result", null)

常见问题

问题原因解决方案
返回栈错乱未设置 launchSingleTop在 navigate 中配置 launchSingleTop
参数解析失败参数类型不匹配使用 navArgument 指定类型
多模块冲突路由名称重复采用命名空间前缀或封装 Destination 类

实战案例:深链是”从外部一脚踹进 App 内页”

Deep Link 的本质一句话:让 https://myapp.com/product/123 这样的链接直接打开 App 的商品详情页,而不是首页。Android 侧分两步:

  1. Manifest 里声明:intent-filter 配 android:scheme="https" + host="myapp.com",系统才知道这个域名归你管。Android 12+ 还要求用 App Links(assetlinks.json 放到域名 .well-known 下做双向验证),否则只能弹选择框,不能直达。
  2. Compose Navigation 里接:composable("product/{id}", deepLinks = listOf(navDeepLink { uriPattern = "https://myapp.com/product/{id}" })),参数自动进 backStackEntry.arguments。

我在 Flutter 里做过对等的事(app_links 包 + go_router 的 deep link),最大的坑是冷启动:App 没在后台时,deeplink 进来要等引擎初始化,页面会先闪一下首页再跳详情——和 Flutter 里路由重定向的时序问题一模一样。解法也一样:启动页(splash)先 hold 住,等路由解析完再放行。

另外提醒:国内 Android 生态的 deeplink 被各厂商 ROM 魔改得很厉害,测试时至少覆盖小米/华为/OV,别只在 Pixel 模拟器上自嗨。

参考:Android 官方文档《Navigation deep links》;《Verify Android App Links》

总结

  1. Compose Navigation 提供声明式路由配置,配合 sealed class 管理更清晰。
  2. 深链需同时配置 Manifest 与导航逻辑,确保参数安全解析。
  3. 在多模块项目中抽象导航接口,避免直接引用具体实现,使路由体系可扩展、可维护。

分享这篇文章



相关文章

上一篇
Android Kotlin Compose 可访问性与无障碍
下一篇
Android Kotlin Compose 动画进阶
YGJoon 的头像

YGJoon

记录 Flutter、Web 与原生移动端工程实践。更多背景见关于页,源码与项目见GitHub。