在 Android 中,深层链接是指将用户直接定向到应用内特定目的地的链接。
您可以在应用中支持两种不同类型的深层链接:显式深层链接和
隐式深层链接。实现深层链接的方式取决于应用使用的图表
类型—XML or programmatic。
创建显式深层链接
显式深层链接是深层链接的一个实例,该实例使用 PendingIntent 将用户定向到应用内的特定位置。例如,您可以在通知或应用 widget 中显示显式深层链接。
当用户通过显式深层链接打开您的应用时,任务返回堆栈会被清除,并被替换为相应的深层链接目的地。当嵌套图表时,每个嵌套级别的起始目的地(即层次结构中每个 <navigation> 元素的起始目的地)也会添加到相应堆栈中。也就是说,当用户从深层链接目的地按下返回按钮时,他们会返回到相应的导航堆栈,就像从入口点进入您的应用一样。
程序化图表
如果您的导航图是以程序化方式定义的(在 Navigation Compose 或 Kotlin DSL 中通常是这样),我们建议您使用 TaskStackBuilder 创建深层链接 PendingIntent。
val id = "exampleId"
val context = LocalContext.current
val deepLinkIntent = Intent(
Intent.ACTION_VIEW,
"https://www.example.com/profile/$id".toUri(),
context,
MyActivity::class.java
)
val pendingIntent: PendingIntent? = TaskStackBuilder.create(context).run {
addNextIntentWithParentStack(deepLinkIntent)
getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT)
}
XML 图表
您可以使用 NavDeepLinkBuilder
类构造 PendingIntent,
如以下示例所示。请注意,如果提供的上下文不是 Activity,构造函数会使用 PackageManager.getLaunchIntentForPackage() 作为默认 activity 启动(如有)。
Kotlin
val pendingIntent = NavDeepLinkBuilder(context) .setGraph(R.navigation.nav_graph) .setDestination(R.id.android) .setArguments(args) .createPendingIntent()
Java
PendingIntent pendingIntent = new NavDeepLinkBuilder(context) .setGraph(R.navigation.nav_graph) .setDestination(R.id.android) .setArguments(args) .createPendingIntent();
默认情况下,NavDeepLinkBuilder 会将显式深层链接启动到应用清单中声明的默认启动 Activity。如果您的 NavHost 在其他 activity 中,则您必须在创建深层链接建立工具时指定其组件名称:
Kotlin
val pendingIntent = NavDeepLinkBuilder(context) .setGraph(R.navigation.nav_graph) .setDestination(R.id.android) .setArguments(args) .setComponentName(DestinationActivity::class.java) .createPendingIntent()
Java
PendingIntent pendingIntent = new NavDeepLinkBuilder(context) .setGraph(R.navigation.nav_graph) .setDestination(R.id.android) .setArguments(args) .setComponentName(DestinationActivity.class) .createPendingIntent();
如果您有 ComponentName,可以直接将其传递给建立工具:
Kotlin
val componentName = ... val pendingIntent = NavDeepLinkBuilder(context) .setGraph(R.navigation.nav_graph) .setDestination(R.id.android) .setArguments(args) .setComponentName(componentName) .createPendingIntent()
Java
ComponentName componentName = ...; PendingIntent pendingIntent = new NavDeepLinkBuilder(context) .setGraph(R.navigation.nav_graph) .setDestination(R.id.android) .setArguments(args) .setComponentName(componentName) .createPendingIntent();
如果您已有 NavController,还可以使用 NavController.createDeepLink() 创建深层链接。
创建隐式深层链接
隐式深层链接是指应用中的特定目的地。调用深层链接(例如,当用户点击某个链接)时,Android 就可以将应用打开到相应的目的地。
可以通过 URI、intent 操作和 MIME 类型匹配深层链接。您可以为单个深层链接指定多个匹配类型,但请注意,匹配的优先顺序依次是 URI 参数、操作和 MIME 类型。
程序化图表
如果您以程序化方式(使用 Navigation Compose 或 Kotlin DSL)定义导航图,则可以在代码中定义深层链接。
Compose
在 Navigation Compose 中,您可以使用 deepLinks 参数将深层链接定义为 composable() 目的地构建器的一部分。它接受
NavDeepLink对象列表,您可以使用
navDeepLink()函数创建这些对象:
@Serializable
data class Profile(val id: String)
val uri = "https://www.example.com"
composable<Profile>(
deepLinks = listOf(
navDeepLink<Profile>(basePath = "$uri/profile")
)
) { backStackEntry ->
val profile: Profile = backStackEntry.toRoute()
ProfileScreen(id = profile.id)
}
Kotlin DSL
使用 Kotlin DSL 时,您可以使用
deepLink() 构建器函数定义深层链接:
@Serializable
data class Profile(val id: String)
val uri = "https://www.example.com"
fragment<ProfileFragment, Profile> {
deepLink<Profile>(basePath = "$uri/profile")
}
为程序化图表添加 intent 过滤器
由于程序化导航图是在运行时构建的,因此 Navigation
组件无法自动生成匹配的 <intent-filter> 元素
在您的 AndroidManifest.xml 中。您必须手动添加相应的
<intent-filter> 元素。
如需启用前面示例中的深层链接,请在清单中相应的
<activity> 元素内添加以下内容:
<activity …>
<intent-filter>
...
<data android:scheme="https" android:host="www.example.com" />
</intent-filter>
</activity>
XML 图表
如需在基于 XML 的图表中创建隐式深层链接,您可以直接在 XML 中定义
<deepLink> 元素,也可以使用 Navigation Editor。
下面是一个包含 URI、操作和 MIME 类型的深层链接示例:
<fragment android:id="@+id/a"
android:name="com.example.myapplication.FragmentA"
tools:layout="@layout/a">
<deepLink app:uri="www.example.com"
app:action="android.intent.action.MY_ACTION"
app:mimeType="type/subtype"/>
</fragment>
您还可以使用 Navigation Editor 创建指向某个目的地的隐式深层链接,如下所示:
- 在 Navigation Editor 的 Design 标签页中,选择深层链接的目的地。
- 点击 Attributes 面板 Deep Links 部分中的 +。
在随后显示的 Add Deep Link 对话框中,输入深层链接的信息。
请注意以下几点:
- 没有架构的 URI 假定为
http或https。例如,www.google.com与http://www.google.com和https://www.google.com都匹配。 - 形式为
{placeholder_name}的路径参数占位符与一个或多个字符相匹配。例如,http://www.example.com/users/{id}与http://www.example.com/users/4匹配。Navigation 组件尝试通过将占位符名称与已定义的 参数(为深层链接目的地所定义)相匹配,将占位值解析为相应的类型。如果没有定义具有相同名称的参数,对参数值使用默认的String类型。您可以使用 .* 通配符匹配 0 个或多个字符。 - 可以使用查询参数占位符代替路径参数,也可以将查询参数占位符与路径参数结合使用。例如,
http://www.example.com/users/{id}?myarg={myarg}与http://www.example.com/users/4?myarg=28匹配。 - 使用默认值或可为 null 的值所定义的变量的查询参数占位符无需匹配。例如,
http://www.example.com/users/{id}?arg1={arg1}&arg2={arg2}与http://www.example.com/users/4?arg2=28或http://www.example.com/users/4?arg1=7匹配。不过,路径参数并非如此。例如,http://www.example.com/users?arg1=7&arg2=28就与上述模式不匹配,因为未提供所需的路径参数。 - 多余的查询参数不会影响深层链接 URI 匹配。例如,即使 URI 模式中未定义
extraneousParam,http://www.example.com/users/{id}也与http://www.example.com/users/4?extraneousParam=7匹配。
- 没有架构的 URI 假定为
(可选)选中 Auto Verify 可要求 Google 验证您是相应 URI 的所有者。如需了解详情,请参阅验证 Android 应用链接。
点击 Add。所选目的地上方会显示链接图标
,用于表示该目的地具有深层链接。点击 Code 标签页,以切换到 XML 视图。已向相应目的地添加嵌套的
<deepLink>元素:<deepLink app:uri="https://www.google.com" />
如需为基于 XML 的图表启用隐式深层链接,您还必须向应用的 manifest.xml 文件中添加内容。将一个 <nav-graph>
元素添加到指向现有导航图的 activity,如以下示例所示:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.myapplication"> <application ... > <activity name=".MainActivity" ...> ... <nav-graph android:value="@navigation/nav_graph" /> ... </activity> </application> </manifest>
构建项目时,Navigation 组件会将 <nav-graph>
元素替换为生成的 <intent-filter> 元素,以匹配导航图中的所有深层链接
。
隐式深层链接和返回堆栈
在触发隐式深层链接时,返回堆栈的状态取决于
是否使用
Intent.FLAG_ACTIVITY_NEW_TASK
标志启动隐式 Intent:
- 如果该标志已设置,任务返回堆栈就会被清除,并被替换为相应的深层链接目的地。与显式深层链接一样,当嵌套图表时,每个嵌套级别的起始目的地(即层次结构中每个
<navigation>元素的起始目的地)也会添加到相应堆栈中。也就是说,当用户从深层链接目的地按下返回按钮时,他们会返回到相应的导航堆栈,就像从入口点进入您的应用一样。 - 如果该标记未设置,您仍会位于触发隐式深层链接时所在的上一个应用的任务堆栈中。在这种情况下,如果按下返回按钮,您会返回到上一个应用;如果按下向上按钮,就会在导航图中的父级目的地上启动应用的任务。
处理深层链接
使用 Navigation 时,强烈建议您始终使用默认
launchMode:standard
。使用 standard 启动模式时,Navigation 会调用 handleDeepLink() 来处理 Intent 中的任何显式或隐式深层链接,从而自动处理深层链接。但是,如果在使用备用 singleTop 等备选 launchMode 时重复使用了相应 Activity,则这不会自动发生。在这种情况下,有必要在 onNewIntent() 中手动调用 handleDeepLink(),如以下示例所示:
Kotlin
override fun onNewIntent(intent: Intent?) { super.onNewIntent(intent) navController.handleDeepLink(intent) }
Java
@Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); navController.handleDeepLink(intent); }