Ste*_*ail 11 android kotlin android-deep-link android-jetpack-compose
当用户在我们的应用程序中进入地理围栏时,我们会向他们显示有关该区域的优惠通知,单击该通知后,应将他们引导至名为 的特定可组合屏幕SingleNotification。我已经遵循了谷歌的代码实验室及其文档,但我还没有设法使到特定屏幕的导航正常工作。现在,单击通知或运行命令adb shell am start -d \xe2\x80\x9ceway://station_offers/date_str/www.test.com/TITLE/CONTENT\xe2\x80\x9d -a android.intent.action.VIEW,只需打开应用程序即可。
该活动在清单中声明如下:
\n <activity\n android:name=".MainActivity"\n android:exported="true"\n android:label="@string/app_name"\n android:screenOrientation="portrait">\n <intent-filter>\n <action android:name="android.intent.action.MAIN" />\n\n <category android:name="android.intent.category.LAUNCHER" />\n\n <category android:name="android.intent.category.DEFAULT" />\n <category android:name="android.intent.category.BROWSABLE" />\n </intent-filter>\n\n <intent-filter>\n <action android:name="android.intent.action.VIEW" />\n\n <category android:name="android.intent.category.DEFAULT" />\n <category android:name="android.intent.category.BROWSABLE" />\n\n <data\n android:host="station_offers"\n android:scheme="eway" />\n </intent-filter>\n </activity>\nRun Code Online (Sandbox Code Playgroud)\n我们的 MainNavController 类包含 NavHost,而 NavHost 又包含各种 NavGraph。我只包含了下面的相关图表:
\n NavHost(\n navController = navController,\n startDestination = NavigationGraphs.SPLASH_SCREEN.route\n ) {\n....\n notificationsNavigation()\n.... \n }\nRun Code Online (Sandbox Code Playgroud)\n通知导航图定义如下:
\nfun NavGraphBuilder.notificationsNavigation() {\n navigation(\n startDestination = Screens.NOTIFICATION_DETAILS.navRoute,\n route = NavigationGraphs.NOTIFICATIONS.route\n ) {\n composable(\n route = "${Screens.NOTIFICATION_DETAILS.navRoute}/{date}/{imageUrl}/{title}/{content}",\n arguments = listOf(\n navArgument("date") { type = NavType.StringType },\n navArgument("imageUrl") { type = NavType.StringType },\n navArgument("title") { type = NavType.StringType },\n navArgument("content") { type = NavType.StringType }\n ),\n deepLinks = listOf(navDeepLink {\n uriPattern = "eway://${Screens.NOTIFICATION_DETAILS.navRoute}/{date}/{imageUrl}/{title}/{content}"\n })\n ) { backstackEntry ->\n val args = backstackEntry.arguments\n SingleNotification(\n date = args?.getString("date")!!,\n imageUrl = args.getString("imageUrl")!!,\n title = args.getString("title")!!,\n description = args.getString("content")!!\n )\n }\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n对应Screes.NOTIFICATION_DETAILS.navRoute于 的值notification_details。
在地理围栏广播接收器内部,我构造待处理的 Intent,如下所示:
\n val deepLinkIntent = Intent(\n Intent.ACTION_VIEW,\n "eway://station_offers/${\n offer.date\n }/${\n offer.image\n }/${offer.title}/${offer.content}".toUri(),\n context,\n MainActivity::class.java\n )\n val deepLinkPendingIntent: PendingIntent =\n TaskStackBuilder.create(context!!).run {\n addNextIntentWithParentStack(deepLinkIntent)\n getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT)!!\n }\n showNotification(offer.title, offer.content, deepLinkPendingIntent)\nRun Code Online (Sandbox Code Playgroud)\n我不知道我在这里错过了什么。
\ncur*_*zen 17
事实证明,这个答案中描述的限制并不完全正确。具体来说,
上面的第 2 点是解锁我对深度链接如何工作的理解的关键。它们只是任意的 URI,与目的地的路由完全没有关系。规则是以下 3 项必须匹配
navDeepLink可组合项的DSL中定义的 URI 模式PendingIntent用于构造通知的URIscheme声明。hostintent-filter这是一些代码片段。在我的例子中,URI 是静态的,因此您需要进行调整以解决 OP 的情况。该示例具有以下结构
LandingScreen( "landing_screen_route")SecondScreen( "second_screen_route")"nested_graph_route") 和NestedScreen( "nested_destination_route")我们将了解如何通过通知到达SecondScreen两者。NestedScreen
首先,使用 DSL 定义 NavGraph。请特别注意navDeepLink此处的条目。
@Composable
fun AppGraph(onNotifyClick: () -> Unit) {
val navController = rememberNavController()
NavHost(
navController = navController,
startDestination = "landing_screen_route"
) {
composable("landing_screen_route") {
LandingScreen {
navController.navigate("second_screen_route")
}
}
composable(
route = "second_screen_route",
deepLinks = listOf(
navDeepLink { uriPattern = "myapp://arbitrary_top_level" } // Note that this pattern has no relation to the route itself
)
) {
SecondScreen {
navController.navigate("nested_graph_route")
}
}
navigation(
startDestination = "nested_destination_route",
route = "nested_graph_route"
) {
composable(
route = "nested_destination_route",
deepLinks = listOf(
navDeepLink { uriPattern = "myapp://arbitrary_nested" } // Note that this pattern has no relation to the route itself
)
) {
NestedScreen(onNotifyClick)
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
接下来,以下是针对这两种情况构建 PendingIntent 的方法:
val notNestedIntent = TaskStackBuilder.create(this).run {
addNextIntentWithParentStack(
Intent(
Intent.ACTION_VIEW,
"myapp://arbitrary_top_level".toUri() // <-- Notice this
)
)
getPendingIntent(1234, PendingIntent.FLAG_UPDATE_CURRENT)
}
val nestedIntent = TaskStackBuilder.create(this).run {
addNextIntentWithParentStack(
Intent(
Intent.ACTION_VIEW,
"myapp://arbitrary_nested".toUri() // <-- Notice this
)
)
getPendingIntent(2345, PendingIntent.FLAG_UPDATE_CURRENT)
}
Run Code Online (Sandbox Code Playgroud)
最后,这是intent-filter清单中的条目
<activity
android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<!--
The scheme and host must match both of the below:
1. The navDeepLink declaration
2. The URI defined in the PendingIntent
-->
<data
android:scheme="myapp"
android:host="arbitrary_top_level"
/>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<!--
The scheme and host must match both of the below:
1. The navDeepLink declaration
2. The URI defined in the PendingIntent
-->
<data
android:scheme="myapp"
android:host="arbitrary_nested"
/>
</intent-filter>
</activity>
Run Code Online (Sandbox Code Playgroud)
更新:请参阅下面@curioustechizen 的答案以获取实际的解决方案,而不是此解决方法!
好吧,经过大量测试并逐行运行 Google 相关代码实验室的解决方案后,我弄清楚了如何使其工作。首先也是最重要的,host我们在 AndroidManifest.xml 中为<data>意图过滤器的标签定义的内容看起来需要很多可组合目标的路由。所以就我而言,它被定义为:
<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:host="notification_details"
android:scheme="eway" />
</intent-filter>
Run Code Online (Sandbox Code Playgroud)
其次,深层链接的 uri 模式应与可组合项的路由格式匹配。在这种情况下,由于可组合项的路由定义为route = "${Screens.NOTIFICATION_DETAILS.navRoute}/{date}/{imageUrl}/{title}/{content}",因此正确的深层链接uriPattern将是:
deepLinks = listOf(navDeepLink {
uriPattern =
"eway://${Screens.NOTIFICATION_DETAILS.navRoute}/{date}/{imageUrl}/{title}/{content}"
})
Run Code Online (Sandbox Code Playgroud)
此外,可组合目的地似乎必须在其NavHost自身内部声明,而不是在 NavGraph 内部声明。最初如您所见,我认为系统能够通过嵌套的 NavGraph 找到目的地,但它不能(抛出相对异常),所以我得出的结论是必须这样做(如是在代码实验室中完成的)。如果我错了请纠正我!
最后,我val uri相应地更改了 GeofenceBroadcastReceiver 内的定义。现在看起来像这样:
val uri = "eway://${Screens.NOTIFICATION_DETAILS.navRoute}/${
offer.date.replace(
"/",
"@"
)
}/${
offer.image.replace(
"/",
"@"
)
}/${offer.title}/${offer.content.replace("/", "@")}".toUri()
Run Code Online (Sandbox Code Playgroud)
回顾一下,据我所知,这些步骤似乎可以解决这个问题:
android:host与目标可组合项的路由匹配,最后,scheme://host/....则遵循数字 2 应该没问题)