如何从app或其他动态功能模块跳转至动态功能模块内的Jetpack Compose函数
方案结论
完全存在不需要依赖Fragment作为中间目的地的纯Compose动态功能模块导航方案,Jetpack Navigation官方已经提供了原生支持,核心依赖DynamicNavHost + 公共路由契约 + SPI服务发现即可实现,无需app模块直接感知动态功能模块的内部实现。
1. 前置依赖配置
在项目根目录的公共基础模块(所有模块都依赖的纯Kotlin/Java模块,无业务逻辑)、app宿主模块、所有动态功能模块中引入导航依赖:
// 模块级build.gradle.kts dependencies { implementation "androidx.navigation:navigation-compose:2.7.5" implementation "androidx.navigation:navigation-dynamic-features-compose:2.7.5" // 可选:如果用Safe Args生成路由类 implementation "androidx.navigation:navigation-safe-args-gradle-plugin:2.7.5" }
2. 公共路由契约层定义
在公共基础模块中定义全局路由常量、参数规范和导航注册接口,避免各模块直接依赖:
// 公共模块中定义 object RouteConstants { const val MAIN_ROUTE = "main" const val LOGIN_ROUTE = "login" const val STAGE_ROUTE = "stage" // 跳转参数常量 const val ARG_USER_SESSION = "sessionArgs" } // 导航注册接口,所有动态模块实现该接口注册自己的导航图 interface NavigationProvider { fun registerNavGraph(navGraphBuilder: NavGraphBuilder, navController: NavHostController) }
3. 动态功能模块实现导航注册
以login动态功能模块为例,实现导航注册接口,注册自身的Compose目的地:
// login模块中 @AutoService(NavigationProvider::class) // 用Google AutoService做SPI服务注册 class LoginNavigationProvider : NavigationProvider { override fun registerNavGraph(navGraphBuilder: NavGraphBuilder, navController: NavHostController) { navGraphBuilder.composable(RouteConstants.LOGIN_ROUTE) { LoginPage( onLoginSuccess = { userSession -> // 跨模块跳转到stage模块,直接用公共路由即可,不需要依赖stage模块 navController.navigate("${RouteConstants.STAGE_ROUTE}?${RouteConstants.ARG_USER_SESSION}=${userSession}") } ) } } }
stage模块的实现逻辑和login模块完全一致,自行注册自身的Compose目的地即可。
4. app宿主模块初始化导航
app模块使用DynamicNavHost替代普通NavHost,通过SPI加载所有动态模块的导航注册实现,完成全局导航图构建:
// app模块的主Activity中 class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { val navController = rememberDynamicNavHostController() DynamicNavHost( navController = navController, startDestination = RouteConstants.MAIN_ROUTE ) { // 先注册app模块自身的目的地 composable(RouteConstants.MAIN_ROUTE) { MainPage( onGoToLogin = { // 直接导航到login模块的路由,不需要感知login模块内部实现 navController.navigate(RouteConstants.LOGIN_ROUTE) } ) } // SPI加载所有动态模块的导航注册实现,批量注册 val navProviders = ServiceLoader.load(NavigationProvider::class.java) navProviders.forEach { provider -> provider.registerNavGraph(this, navController) } } } } }
注意事项
如果动态功能模块未提前安装,导航前需要先通过Play Core API查询模块安装状态,触发下载安装完成后再执行导航操作,避免路由找不到的异常。
内容的提问来源于stack exchange,提问作者Thracian
相关产品推荐
相关产品推荐

