跳转到正文
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 动画进阶