在开放网页上,点一下 Universal Link,系统就有机会打开你的 App;Android 上的 App Link 同理。但在 WebView 里,这次跳转会死掉。WebView 自己加载 URL 时,操作系统根本不会被问到「该由哪个 App 处理」,于是你发布的关联文件(apple-app-site-association / assetlinks.json)永远不会被查阅。对金融 App 来说,这意味着本该把用户推进银行 App 做 3DS / SCA 强客户认证、或推进钱包 App 确认付款的重定向,会悄悄落回网页——甚至什么地方都不去。宿主自有 runtime 桥接原生打开能力,让跳转在每个引擎上都生效。
Universal Link 在 WebView 里从不触发
Universal Link 与 Android App Link 是操作系统级机制。用户在 Safari、Chrome 或系统浏览器里点链接时,iOS / Android 会检查该域名的关联文件,若已安装匹配 App 就直接打开它。这一拦截发生在任何浏览器渲染页面之前。但当 WebView 加载同一个 URL 时,宿主 App 已经开着一个网页视图,直接把它渲染在内部——系统从不被询问,关联文件形同虚设,App 永远不会启动。Apple 文档明确写道:用 WKWebView 处理 Universal Link 会让 iOS 在 Safari 打开网站而非你的 App;只有在已嵌入的视图里由用户点按,链接才可能打开 App,且仍需宿主配合。JavaScript 重定向(window.location.href)不被算作用户主动导航,也会被系统解析器忽略。
自定义 URI Scheme 同样被压制
旧的兜底方案——像 myapp:// 这样的自定义 URI Scheme——在 WebView 里同样不可靠。iOS 上,页面在 WKWebView 内部没有任何受支持的方式强制宿主交出控制权;自定义 Scheme 在多数 WebView 场景被压制,失败且无任何回退。Android 上,裸 WebView 同样不解析 App Link,只有 Android Custom Tabs(真正的浏览器实例)才会。宿主可以在 Android 覆写 shouldOverrideUrlLoading、或在 iOS 实现 decidePolicyFor navigationAction 去调用 UIApplication.open,但大多数 App——尤其是包裹第三方内容的社交与超级 App——并不会这么做,因为把用户留在网页里才是它们的诉求。结果到处一样:页面依赖的跨 App 跳转不会发生。
跳转失败时什么会断
- 3DS / SCA 跳银行 App 失败。 强客户认证常常把手伸给发卡行的 App。在 WebView 里这一跳被吞掉,认证卡住或悄悄回到银行从未完成的网页兜底。
- 钱包与付款确认断链。 「去钱包 App 确认」的链接本应深链进 Google Pay、Apple Pay 或银行 App,结果毫无反应。
- 账号绑定与 OAuth 回调失灵。 「打开验证器 / 银行 App 审批」的流转到空白或死胡同页面。
- 归因与安装承接丢失。 本应跨过安装、把用户送到正确页面的延迟深链断裂,损害激活漏斗。
runtime 的解法
宿主自有 runtime 接管跨 App 跳转。页面只调一个统一 API——runtime.openApp(url)——宿主通过平台原生机制解析:iOS 用 UIApplication.open(配合 Universal Link 或经宿主审校的 Scheme),Android 用 Intent / App Link,并在没有安装目标 App 时给出网页回退。runtime 还能识别自己正处于嵌入式视图,主动暴露「在浏览器打开」的明确入口,而不是一个看似点了没反应的链接。一次集成,每个引擎,一个真正落地的跳转。
| 维度 | WebView | 宿主自有 runtime |
|---|---|---|
| 系统链接解析 | 从不被询问 | 宿主调原生打开 |
| Universal / App Link | 被吞 | 经原生打开生效 |
| 自定义 URI Scheme | 被压制 / 静默失败 | 经宿主审校交接 |
| iOS 出口 | 无可靠方式 | UIApplication.open |
| Android 出口 | 仅 Custom Tabs | Intent / App Link |
| 3DS / 钱包跳转 | 断 | 通 |
| 无目标 App 时 | 无 | 明确网页回退 |
原生 App 能在每台设备上打开另一个 App;裸 WebView 几乎不能。runtime 给页面一个调用——以及一个真正落地的跳转。
参考来源
- Apple Developer — 支持 Universal Links — 用 WKWebView 处理 Universal Link 会在 Safari 打开网站而非 App,系统解析被绕过。
- Apple Developer — UIApplication.open — 宿主必须把 URL 路由出 WebView 时所用的原生 API。
- Deeplinkly — 应用内浏览器里的深链 — WebView 自己加载 URL,系统无从解析;Universal Link 与 App Link 永远到不了声明它的 App。
- LinkRunner — 应用内浏览器如何破坏 Universal/App Link — WKWebView 不触发 Universal Link 拦截;JS 重定向不算用户主动操作而被忽略。
- Tolinku — URI Scheme 与 Universal Link 对比 — 在 App 内部(WKWebView / SFSafariViewController)Universal Link 默认禁用,必须改用
UIApplication.shared.open()。