Compose Multiplatform深层链接跳转DetailScreen失败:无法找到匹配的导航目标
问题重现
你遇到的核心问题是导航框架无法匹配深层链接对应的页面,触发的报错如下:
java.lang.IllegalArgumentException: Navigation destination that matches request NavDeepLinkRequest{ uri=de.ashman.ontrack://detail/1061474/Superman/ https%3A%2F%2Fimage.tmdb.org%2Ft%2Fp%2Foriginal%2FombsmhYUqR4qqOLOxAyr5V8hbyv.jpg/MOVIE } cannot be found in the navigation graph ComposeNavGraph(0x0) startDestination={Destination(0xe19385a7) route=de.ashman.ontrack.navigation.Route.Splash}
从你的代码来看,已经定义了Detail路由和对应的深层链接规则,但即使替换编码后的URL为普通字符串,依然无法匹配成功。
相关代码片段
路由定义
@Serializable @SerialName("detail") data class Detail( val id: String, val title: String, val coverUrl: String, val type: MediaType ) : Route()
导航图配置
fun NavGraphBuilder.mediaGraph( navController: NavController ) { composable<Route.Detail>( typeMap = mapOf( typeOf<MediaNavigationParam>() to CustomNavType.MediaNavigationParamType, typeOf<MediaType>() to CustomNavType.MediaTypeNavType, ), deepLinks = listOf( navDeepLink { uriPattern = "de.ashman.ontrack://detail/{id}/{title}/{coverUrl}/{type}" }, ) ) { backStackEntry -> val detail: Route.Detail = backStackEntry.toRoute() // ... 页面逻辑 } }
深层链接构建代码
"recommendation" -> { val deeplinkUri = Uri.Builder() .scheme("de.ashman.ontrack") .authority("detail") .appendPath(data["mediaId"].toString()) .appendPath(data["mediaTitle"].toString()) .appendPath(data["mediaCoverUrl"].toString()) .appendPath(data["mediaType"].toString()) .build() deeplinkUri.toString() }
最终解决方案
经过排查,问题由两个点共同导致,对应的修复方法如下:
配置Activity启动模式
在AndroidManifest.xml中为主Activity添加android:launchMode="singleTop",避免点击通知时重建整个应用,确保导航控制器能识别已存在的导航图:<activity android:name=".MainActivity" android:launchMode="singleTop" <!-- 其他原有配置 --> > </activity>为枚举类型
MediaType自定义NavType
由于Compose Navigation在iOS端对枚举的解析支持有限,需要自定义NavType来处理MediaType的序列化与反序列化:val MediaTypeNavType = object : NavType<MediaType>(isNullableAllowed = false) { override fun get(bundle: SavedState, key: String): MediaType? { return bundle.read { getString(key).let { MediaType.valueOf(it) } } } override fun parseValue(value: String): MediaType { return MediaType.valueOf(value) } override fun put(bundle: SavedState, key: String, value: MediaType) { bundle.write { putString(key, value.name) } } override fun serializeAsValue(value: MediaType): String { return value.name } }
内容来源于stack exchange

