App 里看不见的 route · deep link / Universal Link
路由也存在于没有地址栏的地方。点一条链接想直接跳进 App 的某个页面(而不是首页),这叫 deep link。它面对一道天生的分叉:装了 App 就进 App,没装就退回网页或去商店。同一条链接,要让两种用户都不落空——这正是 deep link 路由设计的全部难点。
1 · 两种链接形态的取舍
| 维度 | 自定义 scheme · myapp:// |
Universal Link / App Link · https:// |
|---|---|---|
| 谁来接 | App 注册了该 scheme 才有人接 | 系统按域名归属表把 https 路由进 App |
| 没装 App | 无人响应 → 报错 / 白屏 ✗ | 就是一条普通网址,照常开网页 ✓ |
| 归属校验 | 任何 App 都能抢注同名 scheme,易被劫持 ✗ | 靠服务器上的 AASA / assetlinks.json 双向验证 ✓ |
| 体验 | 可能先闪一下浏览器 | 系统层直接进 App,不闪 ✓ |
| 配置成本 | 低,App 端声明即可 | 高,要在域名根部署关联文件 |
iOS = Universal Links (apple-app-site-association);Android = App Links (assetlinks.json)。自定义 scheme 仍用于 App 间互调与回退方案,但作为对外分享入口,Universal Link / App Link 是首选。
deferred deep link(延迟深链)。 最棘手的是「没装 App 的新用户」:你既想让他去商店装,又想让他装完直接到原本想去的那个页面(比如朋友分享的某件商品),而不是丢到 App 首页。做法:落地网页先把目标 (product/42) 暂存(剪贴板 / 设备指纹 /
服务端配对),引导去商店;App 首次启动时读回这个目标,再路由过去。这就把「装 App」这道坎对用户透明化了——归因 SDK(如 AppsFlyer / Branch)干的核心就是这件事。
2 · 本质:还是「稳定入口 ↔ 可变目标 + 匹配」
deep link 看着特殊,内核和前面几页一模一样:myapp://product/42 或 https://vega.link/product/42 里的 product/42 就是一条 path,App 内部同样有一张路由表把它匹配到对应的页面组件 (:id = 42)——和匹配引擎那页是同一套机制,只不过这张表跑在 App 里、对用户不可见。而「装了走 App、没装走网页」这道分叉,本质又是一次按条件选择目标的路由决策。
3 · 相关页
- 本系列 · 路由匹配引擎——App 内部把
product/42匹配到页面、提取:id,用的就是这套 path → handler 引擎。 - 本系列 · 分享地址统一入口——真实分享入口常先判 User-Agent:手机走 deep link、桌面走网页——入口处的多端分流。
- Apple · Universal Links · developer.apple.com——iOS 把 https 链接路由进 App 的官方机制(Android 侧对应 App Links)。