8、深层链接(DeepLink):什么是深层链接?隐式深层链接与显式深层链接、在导航图中配置DeepLink、处理PendingIntent
深层链接,说白了就是让用户从App外部直接跳转到App内部的某个具体页面。比如你收到一条短信,里面有个链接,点一下就直接打开了App的订单详情页,而不是只打开首页。这个能力在Android开发里非常重要,尤其是做分享、推送通知、网页跳转这些场景。
我在项目中遇到过好几次这样的需求:用户收到一条促销推送,点进去应该直接看到商品详情,而不是先看到首页再手动点进去。如果不用深层链接,你得写一堆Intent解析逻辑,还容易出bug。Navigation组件帮我们把这个过程标准化了,省了不少事。
什么是深层链接?
深层链接是一种让外部应用或系统能够直接打开App内特定页面的机制。它有两种形式:
- 显式深层链接:直接指定目标Activity和Fragment,通常用于App内部跳转
- 隐式深层链接:通过URL Scheme或Intent Filter匹配,由系统决定谁来处理
你想想看,如果没有深层链接,用户每次都要从首页开始导航,体验很差。深层链接就是给App的每个页面一个“门牌号”,外部可以直接敲门进来。
核心要点:深层链接的本质是“外部入口”,它让App的页面不再是孤岛,而是可以被外部世界直接访问的资源。
隐式深层链接与显式深层链接
这两种方式在实际开发中各有用途,我分别说一下。
显式深层链接
显式深层链接就是直接指定目标。比如你在代码里这样写:
val intent = Intent(this, DetailActivity::class.java)
intent.putExtra("itemId", 123)
startActivity(intent)
这种方式简单直接,但缺点也很明显:你必须知道目标Activity的类名,而且只能在App内部使用。外部应用没法调用,因为外部不知道你的类名。
隐式深层链接
隐式深层链接是通过URL Scheme或Intent Filter来匹配的。比如你在AndroidManifest里声明一个Scheme:
<activity android:name=".DetailActivity">
<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:scheme="myapp"
android:host="detail" />
</intent-filter>
</activity>
这样外部应用就可以通过 myapp://detail?itemId=123 这个链接来打开你的页面了。系统会找到所有能处理这个链接的Activity,然后让用户选择或者直接打开。
我的建议:在实际项目中,我通常两种方式都用。显式链接用于App内部导航,隐式链接用于外部跳转。这样既保证了内部效率,又开放了外部入口。
在导航图中配置DeepLink
Navigation组件让深层链接的配置变得非常优雅。你不需要在AndroidManifest里写一堆Intent Filter,直接在导航图里声明就行。
举个例子,我有一个商品详情页的导航目标:
<fragment
android:id="@+id/productDetailFragment"
android:name="com.example.app.ProductDetailFragment"
android:label="商品详情">
<deepLink
app:uri="myapp://product/{productId}" />
<argument
android:name="productId"
app:argType="string" />
</fragment>
这里的关键是 <deepLink> 标签。它声明了这个Fragment可以响应 myapp://product/{productId} 这个链接。花括号里的 {productId} 是占位符,会自动映射到argument里。
配置好之后,你还需要在宿主Activity里处理这个链接。Navigation组件提供了一个便捷方法:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val navController = findNavController(R.id.nav_host_fragment)
// 处理来自Intent的深层链接
navController.handleDeepLink(intent)
}
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
// 如果App已经在运行,通过新Intent处理深层链接
findNavController(R.id.nav_host_fragment).handleDeepLink(intent)
}
嗯,这里要注意:handleDeepLink 方法会自动解析Intent里的数据,匹配导航图里声明的deepLink,然后导航到对应的Fragment。你不需要自己写解析逻辑。
我曾经踩过的坑:如果App已经在后台运行,新的深层链接会通过 onNewIntent 进来,而不是 onCreate。所以两个方法都要处理,否则用户从推送通知点进来时,页面不会跳转。
处理PendingIntent
PendingIntent是Android里一个很特殊的东西。它本质上是一个“未来的Intent”,可以被其他应用(比如系统通知栏)在将来某个时刻执行。深层链接经常和PendingIntent配合使用,尤其是在推送通知场景。
比如你收到一条推送,点击后要打开商品详情页。这时候你需要构建一个PendingIntent:
// 构建深层链接的Intent
val deepLinkIntent = Intent(
Intent.ACTION_VIEW,
"myapp://product/123".toUri(),
this,
MainActivity::class.java
)
// 创建PendingIntent
val pendingIntent = PendingIntent.getActivity(
this,
0,
deepLinkIntent,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
)
// 构建通知
val notification = NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle("新品上架")
.setContentText("点击查看商品详情")
.setSmallIcon(R.drawable.ic_notification)
.setContentIntent(pendingIntent)
.setAutoCancel(true)
.build()
NotificationManagerCompat.from(this).notify(NOTIFICATION_ID, notification)
这里有几个关键点:
- FLAG_IMMUTABLE:Android 12开始推荐使用,防止PendingIntent被修改
- FLAG_UPDATE_CURRENT:如果同一个PendingIntent已经存在,更新它的内容
- setAutoCancel(true):点击通知后自动移除,避免重复点击
为什么用PendingIntent而不是直接启动Activity?因为通知栏是系统服务,它不能直接调用你的Activity。PendingIntent相当于一个“授权令牌”,系统拿着这个令牌可以在合适的时候帮你启动页面。
我的经验:在构建PendingIntent时,一定要把深层链接的URI放在Intent的data里,而不是作为extra。因为系统解析深层链接时,会优先看data字段。我曾经把参数放在extra里,结果死活跳转不对,排查了半天才发现是这个问题。
知识体系图
下面这张图展示了深层链接的整体结构和处理流程,你可以对照着理解:
从这张图可以看出来,深层链接的流程其实很清晰:外部入口进来,经过显式或隐式匹配,然后通过导航图配置或PendingIntent处理,最终到达目标页面。Navigation组件帮我们把中间这些步骤都封装好了,你只需要关注业务逻辑就行。
总结一下:深层链接是单Activity架构中非常重要的能力。它让App的页面可以被外部直接访问,提升了用户体验。Navigation组件提供了声明式的配置方式,配合PendingIntent可以轻松实现推送通知、网页跳转等场景。我在实际项目中几乎每个版本都会用到这个功能,建议你熟练掌握。
公众号:蓝海资料掘金营,微信deep3321