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里,结果死活跳转不对,排查了半天才发现是这个问题。

知识体系图

下面这张图展示了深层链接的整体结构和处理流程,你可以对照着理解:

深层链接(DeepLink)知识体系 外部入口 推送通知 · 网页链接 · 短信链接 · 其他App调用 显式深层链接 直接指定目标Activity/Fragment 用于App内部导航 隐式深层链接 通过URL Scheme / Intent Filter匹配 用于外部跳转 导航图配置 <deepLink app:uri="..." /> PendingIntent处理 通知栏 · 桌面小部件 · 其他系统服务 目标Fragment / Activity

从这张图可以看出来,深层链接的流程其实很清晰:外部入口进来,经过显式或隐式匹配,然后通过导航图配置或PendingIntent处理,最终到达目标页面。Navigation组件帮我们把中间这些步骤都封装好了,你只需要关注业务逻辑就行。

总结一下:深层链接是单Activity架构中非常重要的能力。它让App的页面可以被外部直接访问,提升了用户体验。Navigation组件提供了声明式的配置方式,配合PendingIntent可以轻松实现推送通知、网页跳转等场景。我在实际项目中几乎每个版本都会用到这个功能,建议你熟练掌握。


公众号:蓝海资料掘金营,微信deep3321