PWA 深度链接(Deep Linking)实操指南:Android、iOS 与投放参数保留(2026)
PWA 深度链接(Deep Linking for PWA) 和原生 App 的深链不是一回事。PWA 没有自定义 URL scheme,也没有应用商店包名可以跳转——它的每个页面本来就是一个普通的 HTTPS 地址。真正的难点不在「生成链接」,而在让系统把链接打开在已安装的 PWA 里而不是浏览器标签页里,以及让投放参数在安装前后不丢。本文讲清 Android 上怎么捕获链接、iOS 能做什么不能做什么、UTM 参数如何穿过安装环节,以及投放前怎么把整条链路测一遍。
一句话答案: 在 PWA 里,manifest scope 范围内的任何 URL 都是深链。Android 上 Chrome 会把已安装的 PWA 生成为 WebAPK,其 intent filter 覆盖该 scope,所以从其他 App 点开范围内的链接可以直接拉起 PWA(受 Android 版本和用户链接设置影响)。iOS 上,在主屏 Web App 之外点的链接会在 Safari 里打开,不会进入已安装的 Web App。投放链接要按两种情况都能用来设计。PWA 里的深度链接到底是什么
原生 App 的深链是一个特殊地址(自定义 scheme 如 myapp://product/42,或经过验证的 App Links / Universal Links),由系统交给 App 处理。PWA 不需要这层转换:https://shop.example.com/product/42 本身就是深链。安装之后这个 URL 怎么表现,由 manifest 里三个字段决定:
|
Manifest 字段 |
管什么 |
对深链的意义 |
|---|---|---|
|
|
哪些 URL 属于这个应用 |
只有范围内的 URL 能在应用窗口中打开;超出范围会离开应用界面 |
|
|
点主屏图标时打开的页面 |
安装后唯一确定的入口,也是打来源标记的最佳位置 |
|
|
应用身份 |
保持稳定,否则改了 |
一个可深链的 PWA 最小 manifest:
{
"name": "Example Shop",
"id": "/",
"start_url": "/?source=pwa",
"scope": "/",
"display": "standalone",
"icons": [{ "src": "/icon-512.png", "sizes": "512x512", "type": "image/png" }]
}如果 scope 是 /app/,那么 /blog/ 下的链接永远不会在已安装应用里打开。对投放来说最简单的规则是:所有投放出去的落地页、商品页 URL 都放进 scope 里。 浏览器实际会检查哪些字段,见 PWA Manifest 必填字段。
Android 上的 PWA 深度链接:已安装应用如何捕获链接
WebAPK 的 intent filter
用户在 Android 版 Chrome 里安装 PWA 时,Chrome 通常会生成一个 WebAPK——根据你的 manifest 自动生成的小型 Android 安装包。WebAPK 会为你的域名和 scope 声明 intent filter,正因如此,在聊天软件、邮件客户端或其他 App 里点到的链接才能直接打开已安装的 PWA。
会改变结果的几个因素:
- Android 版本与链接验证。 从 Android 12 开始,未经验证的网页链接默认在默认浏览器中打开,除非用户在该应用设置里开启了「打开支持的链接」。所以同一个 WebAPK 链接在不同设备上可能进 App,也可能进浏览器。要在目标人群常用的 Android 版本上实测。
- 在 Chrome 标签页内点击。 在普通 Chrome 标签页里点范围内的链接,一般仍停留在标签页。拉起已安装应用靠的是来自浏览器外部的 intent,而不是每一次页面跳转。
- 安装后修改 manifest。 Chrome 检测到某些 manifest 变化后会更新 WebAPK,但不是即时的。投放进行中不要改
scope或id。
launch_handler、handle_links 与 capture_links
这几个字段在深链教程里常被提到,但实现状态各不相同,写法要保守:
launch_handler(client_mode取值如navigate-existing、focus-existing)控制启动时复用已打开的应用窗口还是新开一个。它已在桌面版 Chromium 中上线;Android 和其他浏览器的支持有限或行为不同。只把它当渐进增强,不要当唯一机制。handle_links是一个提案,用于声明 PWA 是否希望捕获指向其 scope 的链接。按实验性功能对待。capture_links是更早的提案,基本已被launch_handler取代。不要基于它设计投放链路。
截至 2026 年,各字段的实现状态请以 Chrome Platform Status(chromestatus.com)和 MDN 为准,依赖之前先核对——这部分浏览器行为已经变过好几次。
{
"launch_handler": { "client_mode": ["navigate-existing", "auto"] }
}Digital Asset Links:TWA 的不同之处
TWA(Trusted Web Activity) 是一个真正的 Android 应用(用 Bubblewrap 或 Android Studio 构建),全屏展示你的 PWA。因为它是你自己控制的安装包,可以声明经过验证的 Android App Links:在域名下发布 /.well-known/assetlinks.json,写入包名和签名证书指纹,由 Android 完成关联验证。验证通过的链接会直接打开 TWA,不弹选择器。
WebAPK 由 Chrome 生成,intent filter 和签名都不归你管。两者的取舍:
|
|
已安装 PWA(WebAPK) |
TWA |
|---|---|---|
|
分发方式 |
浏览器内安装 |
应用商店或 APK 分发 |
|
链接捕获 |
根据 manifest scope 生成的 intent filter |
通过 Digital Asset Links 验证的 App Links |
|
对链接行为的控制 |
有限,取决于 Chrome 和 Android |
更高,Android manifest 由你掌握 |
|
发版成本 |
部署网站即可 |
需构建、签名、发布 Android 应用 |
更完整的对比见 PWA 与 TWA 的区别。
iOS 上的 PWA 深度链接:限制在哪里
iOS 支持通过 Safari 的分享菜单把网页应用添加到主屏幕(较新版本中,其他使用系统分享面板的浏览器也可以)。但在深链上有明显短板:
- 外部链接打不开主屏应用。 在信息、邮件或社交 App 里点链接,会在 Safari(或 App 内置浏览器)中打开,即使同一个站点已经装到主屏。iOS 没有类似 WebAPK 的 intent 捕获,Universal Links 只服务原生应用。
- 存储是隔离的。 主屏应用有自己独立的存储,与 Safari 分开。安装前在 Safari 里写入的
localStorage或 cookie,在已安装应用里通常读不到。 - 入口就是
start_url。 从图标打开会加载start_url(不同系统版本下也可能是添加时的页面),不会自动落到广告承诺的那个商品页,除非你主动路由过去。
iOS 上仍然能做的事:
- 保证每个深链在 Safari 里都能正常用。 链接在普通浏览器标签页里必须展示正确内容——无论是否安装,这都是 iOS 用户的默认体验。
- 按账号续接,而不是按设备存储。 用户登录后,把目标页面存在服务端,在主屏应用内登录完成时再跳转过去。
- 用 Web Push 把用户带回应用。 从 iOS 16.4 起,主屏 Web App 可以接收推送通知,点击通知会在已安装应用中打开你指定的 URL。这是把 iOS 已安装用户送到指定页面最可靠的方式。
- 给出「从主屏幕打开」的简短提示。 当在 Safari 里识别出该用户此前已安装过(例如依据登录态标记),在页面上提示一句。
iOS 的安装提示需要用户手动操作,如何引导见 添加到主屏幕提示。
安装前后如何保留深链参数与 UTM
延迟深链(deferred deep linking)指的是:用户点广告、安装,首次打开时依然知道他从哪里来、本来想去哪个页面。PWA 没有类似 Google Play 安装来源(install referrer)的接口,需要自己搭。
第 1 步:在落地页捕获参数
// 在首次浏览时、安装提示之前运行
const params = new URLSearchParams(location.search);
const keys = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_content', 'gclid', 'fbclid', 'ttclid'];
const attribution = {};
keys.forEach(k => { if (params.get(k)) attribution[k] = params.get(k); });
if (Object.keys(attribution).length) {
attribution.landing_path = location.pathname;
attribution.ts = Date.now();
localStorage.setItem('attribution', JSON.stringify(attribution));
}在 Android Chrome 上,WebAPK 与浏览器共用同一域名下的存储,首次启动时一般能读到这个值;iOS 上读不到,所以第 3 步很关键。
第 2 步:给主屏启动打标
在 start_url 里加来源标记(例如 /?source=pwa),并在运行时判断显示模式:
const isStandalone = window.matchMedia('(display-mode: standalone)').matches
|| window.navigator.standalone === true;这样数据分析里就能把浏览器会话和已安装应用会话分开。同一个应用身份下 start_url 保持固定;按访客动态生成 manifest 技术上可行,但会让缓存和应用身份变复杂,也很难排查。
第 3 步:落到服务端
用户安装时(Chromium 会触发 appinstalled 事件)或注册时,把存下来的归因对象发给后端,绑定到用户或第一方 ID 上。在 iOS 上,衔接 Safari 与主屏应用的可行办法是:安装后步骤 URL 里带一个短时效 token,或者让用户登录账号。
第 4 步:首次启动的路由
首次以 standalone 模式启动时,读取存好的 landing_path(或从服务端取),跳转一次,然后清掉标记,之后的启动照常打开首页。
每个环节的数据怎么量,见 如何衡量添加到主屏幕转化。
广告投放落地链路怎么设计
PWA 投放的深链链路通常有四跳,每一跳都可能丢参数或丢用户:
|
环节 |
常见问题 |
怎么处理 |
|---|---|---|
|
广告点击 → 落地页 URL |
跳转链把查询参数吃掉 |
尽量少跳转,实测最终 URL 仍带 UTM |
|
社交 App 内置浏览器 |
内嵌 webview 里无法安装 |
识别 webview,提供「在浏览器中打开」步骤;Android 上用 |
|
落地页 → 安装 |
安装提示没出现或被关闭 |
在用户有一定互动后再展示安装入口,见 Chrome 安装提示优化 |
|
安装 → 首次启动 |
打开的是 |
用存好的 |
为这条链路设计的 PWA 落地页 应当在首屏兑现广告内容、在任何其他逻辑之前先捕获参数,并把安装当成其中一步,而不是终点。
如何测试与排查 PWA 深链
Android:
- 在 Chrome 中打开
chrome://webapks,确认 WebAPK 已生成并查看详情。 - 用连接的设备发起一个链接 intent,模拟从其他 App 点击:
adb shell am start -a android.intent.action.VIEW -d "$DEEP_LINK_URL"- 如果打开的是 Chrome 而不是应用,逐项检查:URL 是否在
scope内?应用的 Android 设置里是否开启了「打开支持的链接」?PWA 是否以 WebAPK 形式安装(而不只是主屏快捷方式)? - Android 12 及以上,
adb shell pm get-app-links <package>可以查看已安装包(包括 TWA)的链接验证状态。
iOS:
- 从 Safari 安装后,逐个测试入口:点图标、点推送通知、在信息 App 里点链接(预期在 Safari 打开)。
- 确认主屏应用读不到 Safari 的存储,并验证服务端兜底能还原目标页面。
通用:
- Chrome DevTools 的 Application > Manifest 面板会显示解析后的
scope、start_url、id以及警告。 - 首次启动时记录
display-mode、完整落地页 URL 和存下来的归因对象。大部分「深链丢了」的问题,最后都是参数被吃掉或 URL 超出 scope。
常见问题
PWA 支持深度链接吗?
支持。PWA 的每个页面都有 URL,链接到指定页面天然可行。不同的是系统会把链接打开在已安装应用里还是浏览器里:Android 可以把范围内的链接交给已安装的 WebAPK,iOS 会在 Safari 中打开外部链接。
iPhone 上能用链接直接打开已安装的 PWA 吗?
从其他 App 点链接不行,主屏 Web App 之外的链接会在 Safari 中打开。点击 Web Push 通知可以打开已安装应用,用户启动后也可以通过 start_url 路由到正确页面。
PWA 深链和 Android App Links 有什么区别?
Android App Links 通过 Digital Asset Links(assetlinks.json)验证,需要一个你自己控制的 Android 安装包,比如 TWA。已安装 PWA 依赖 Chrome 生成的 WebAPK,链接处理取决于 Chrome、Android 版本和用户设置。
PWA 安装后怎么保留 UTM 参数?
安装前在落地页存下来(Android 用 localStorage,iOS 走服务端),在 start_url 里加来源标记,在安装或注册时把存下的值发到后端,再把首次 standalone 启动路由到保存的落地页路径。
Android 上支持 launch_handler 吗?
不同平台和浏览器的支持不一样,而且一直在变。截至 2026 年,更适合把它当作桌面版 Chromium 的增强能力;依赖之前请核对 Chrome Platform Status 和 MDN,并确保没有它时链接也能正常工作。
总结
PWA 深度链接的核心是 scope、路由和持久化:所有投放 URL 放进 manifest scope;预期 Android 只在满足条件时捕获链接;默认 iOS 会在 Safari 中打开链接;归因参数需要自己穿过安装环节。ROIBest 提供面向广告投放的 PWA 搭建与分发工具,包括安装流程和转化追踪,适合不想从零拼这条链路的团队。


