使用 Jetpack Compose 的深层链接导航到可组合项
Navigating to a composable using a deeplink with Jetpack Compose
当用户在我们的应用程序中输入地理围栏时,我们会向他们显示有关该区域的优惠通知,单击该通知后,应将他们引导至名为 SingleNotification
的特定可组合屏幕。我已经关注了 google 的 codelab and their documentation,但我还没有成功地导航到特定的屏幕。现在,单击通知或 运行 adb shell am start -d “eway://station_offers/date_str/www.test.com/TITLE/CONTENT” -a android.intent.action.VIEW
命令,只需打开应用程序。
activity在清单中声明如下:
<activity
android:name=".MainActivity"
android:exported="true"
android:label="@string/app_name"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
</intent-filter>
<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="station_offers"
android:scheme="eway" />
</intent-filter>
</activity>
我们的 MainNavController class 包含 NavHost,后者又包含各种 NavGraph。我只包含了下面的相关图表:
NavHost(
navController = navController,
startDestination = NavigationGraphs.SPLASH_SCREEN.route
) {
....
notificationsNavigation()
....
}
通知导航图定义如下:
fun NavGraphBuilder.notificationsNavigation() {
navigation(
startDestination = Screens.NOTIFICATION_DETAILS.navRoute,
route = NavigationGraphs.NOTIFICATIONS.route
) {
composable(
route = "${Screens.NOTIFICATION_DETAILS.navRoute}/{date}/{imageUrl}/{title}/{content}",
arguments = listOf(
navArgument("date") { type = NavType.StringType },
navArgument("imageUrl") { type = NavType.StringType },
navArgument("title") { type = NavType.StringType },
navArgument("content") { type = NavType.StringType }
),
deepLinks = listOf(navDeepLink {
uriPattern = "eway://${Screens.NOTIFICATION_DETAILS.navRoute}/{date}/{imageUrl}/{title}/{content}"
})
) { backstackEntry ->
val args = backstackEntry.arguments
SingleNotification(
date = args?.getString("date")!!,
imageUrl = args.getString("imageUrl")!!,
title = args.getString("title")!!,
description = args.getString("content")!!
)
}
}
}
Screes.NOTIFICATION_DETAILS.navRoute
对应notification_details
的值。
在地理围栏广播接收器中,我构造了如下的未决Intent:
val deepLinkIntent = Intent(
Intent.ACTION_VIEW,
"eway://station_offers/${
offer.date
}/${
offer.image
}/${offer.title}/${offer.content}".toUri(),
context,
MainActivity::class.java
)
val deepLinkPendingIntent: PendingIntent =
TaskStackBuilder.create(context!!).run {
addNextIntentWithParentStack(deepLinkIntent)
getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT)!!
}
showNotification(offer.title, offer.content, deepLinkPendingIntent)
我不知道我在这里遗漏了什么。
好吧,经过大量测试和 运行 Google 的相关代码实验室的解决方案,一行一行地进行了多次测试,我想出了如何让它工作的方法。
首先,看起来我们在 AndroidManifest.xml 中为 intent 过滤器的 <data>
标签定义的 host
需要很多可组合目的地的路由。所以在我的例子中,它被定义为:
<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>
其次,深度 link 的 uri 模式应与可组合项的路由格式相匹配。在这种情况下,由于可组合项的路由定义为 route = "${Screens.NOTIFICATION_DETAILS.navRoute}/{date}/{imageUrl}/{title}/{content}"
,正确的深度 Link uriPattern
将是:
deepLinks = listOf(navDeepLink {
uriPattern =
"eway://${Screens.NOTIFICATION_DETAILS.navRoute}/{date}/{imageUrl}/{title}/{content}"
})
此外,可组合目的地似乎必须在 NavHost
本身内声明,而不是在 NavGraph 内声明。最初如你所见,我认为系统可以通过嵌套的 NavGraph 找到目的地,但它不能(抛出一个相对的异常),所以我得出的结论是它必须以这种方式完成(如在代码实验室中完成)。如有错误请指正!
最后,我相应地更改了 GeofenceBroadcastReceiver 中的 val uri
定义。现在看起来像这样:
val uri = "eway://${Screens.NOTIFICATION_DETAILS.navRoute}/${
offer.date.replace(
"/",
"@"
)
}/${
offer.image.replace(
"/",
"@"
)
}/${offer.title}/${offer.content.replace("/", "@")}".toUri()
总结一下,据我所知,这些步骤似乎可以解决这个问题:
- 深层 link 的目标可组合项必须是主 NavHost
的直接子项
- AndroidManifest 的
android:host
应该匹配目标可组合项的路由,最后,
- 深层 link 的 URI 模式应与目标可组合项的路由相匹配(如果您使用
scheme://host/....
格式,则遵循数字 2 应该没问题)
当用户在我们的应用程序中输入地理围栏时,我们会向他们显示有关该区域的优惠通知,单击该通知后,应将他们引导至名为 SingleNotification
的特定可组合屏幕。我已经关注了 google 的 codelab and their documentation,但我还没有成功地导航到特定的屏幕。现在,单击通知或 运行 adb shell am start -d “eway://station_offers/date_str/www.test.com/TITLE/CONTENT” -a android.intent.action.VIEW
命令,只需打开应用程序。
activity在清单中声明如下:
<activity
android:name=".MainActivity"
android:exported="true"
android:label="@string/app_name"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
</intent-filter>
<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="station_offers"
android:scheme="eway" />
</intent-filter>
</activity>
我们的 MainNavController class 包含 NavHost,后者又包含各种 NavGraph。我只包含了下面的相关图表:
NavHost(
navController = navController,
startDestination = NavigationGraphs.SPLASH_SCREEN.route
) {
....
notificationsNavigation()
....
}
通知导航图定义如下:
fun NavGraphBuilder.notificationsNavigation() {
navigation(
startDestination = Screens.NOTIFICATION_DETAILS.navRoute,
route = NavigationGraphs.NOTIFICATIONS.route
) {
composable(
route = "${Screens.NOTIFICATION_DETAILS.navRoute}/{date}/{imageUrl}/{title}/{content}",
arguments = listOf(
navArgument("date") { type = NavType.StringType },
navArgument("imageUrl") { type = NavType.StringType },
navArgument("title") { type = NavType.StringType },
navArgument("content") { type = NavType.StringType }
),
deepLinks = listOf(navDeepLink {
uriPattern = "eway://${Screens.NOTIFICATION_DETAILS.navRoute}/{date}/{imageUrl}/{title}/{content}"
})
) { backstackEntry ->
val args = backstackEntry.arguments
SingleNotification(
date = args?.getString("date")!!,
imageUrl = args.getString("imageUrl")!!,
title = args.getString("title")!!,
description = args.getString("content")!!
)
}
}
}
Screes.NOTIFICATION_DETAILS.navRoute
对应notification_details
的值。
在地理围栏广播接收器中,我构造了如下的未决Intent:
val deepLinkIntent = Intent(
Intent.ACTION_VIEW,
"eway://station_offers/${
offer.date
}/${
offer.image
}/${offer.title}/${offer.content}".toUri(),
context,
MainActivity::class.java
)
val deepLinkPendingIntent: PendingIntent =
TaskStackBuilder.create(context!!).run {
addNextIntentWithParentStack(deepLinkIntent)
getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT)!!
}
showNotification(offer.title, offer.content, deepLinkPendingIntent)
我不知道我在这里遗漏了什么。
好吧,经过大量测试和 运行 Google 的相关代码实验室的解决方案,一行一行地进行了多次测试,我想出了如何让它工作的方法。
首先,看起来我们在 AndroidManifest.xml 中为 intent 过滤器的 <data>
标签定义的 host
需要很多可组合目的地的路由。所以在我的例子中,它被定义为:
<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>
其次,深度 link 的 uri 模式应与可组合项的路由格式相匹配。在这种情况下,由于可组合项的路由定义为 route = "${Screens.NOTIFICATION_DETAILS.navRoute}/{date}/{imageUrl}/{title}/{content}"
,正确的深度 Link uriPattern
将是:
deepLinks = listOf(navDeepLink {
uriPattern =
"eway://${Screens.NOTIFICATION_DETAILS.navRoute}/{date}/{imageUrl}/{title}/{content}"
})
此外,可组合目的地似乎必须在 NavHost
本身内声明,而不是在 NavGraph 内声明。最初如你所见,我认为系统可以通过嵌套的 NavGraph 找到目的地,但它不能(抛出一个相对的异常),所以我得出的结论是它必须以这种方式完成(如在代码实验室中完成)。如有错误请指正!
最后,我相应地更改了 GeofenceBroadcastReceiver 中的 val uri
定义。现在看起来像这样:
val uri = "eway://${Screens.NOTIFICATION_DETAILS.navRoute}/${
offer.date.replace(
"/",
"@"
)
}/${
offer.image.replace(
"/",
"@"
)
}/${offer.title}/${offer.content.replace("/", "@")}".toUri()
总结一下,据我所知,这些步骤似乎可以解决这个问题:
- 深层 link 的目标可组合项必须是主 NavHost 的直接子项
- AndroidManifest 的
android:host
应该匹配目标可组合项的路由,最后, - 深层 link 的 URI 模式应与目标可组合项的路由相匹配(如果您使用
scheme://host/....
格式,则遵循数字 2 应该没问题)