Skip to content

Commit b46dfb6

Browse files
committed
new file: _posts/2017-12-24-launch-app-from-browser.md
1 parent 4f29ae2 commit b46dfb6

File tree

4 files changed

+142
-0
lines changed

4 files changed

+142
-0
lines changed
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
---
2+
title: Deep Linking:从浏览器调起 APP
3+
subtitle: URI Scheme, Universal Links, Android App Links, 以及 Chrome Intent
4+
---
5+
6+
[Deep Linking][deep-linking] 只是一个概念,
7+
是指通过一个链接进入另一个网站/App,并直接浏览其内部的某个页面。
8+
Deep Linking 给用户带来的是非常顺滑的浏览体验,尤其在 Web 世界中 Deep Linking 的实现非常容易。
9+
10+
但如果要进入 App 并定位到对应的页面则较为困难,URI Scheme, Universal Links, Android App Links, 以及 Chrome Intent 都是为了解决从 Web 页面 Deep Linking 到 App 而做的尝试。
11+
本文从 Web 一侧的视角总结调起 App 的各种实现方式,能达到的效果,以及对应的兼容性问题。
12+
13+
## 实现方式概述
14+
15+
每种实现方式都有其适用的平台和浏览器,要兼容多数浏览器需要根据 User Agent 应用不同的策略。
16+
这些实现方式的行为也不一致,可能需要配合产品需求才能确定结合哪几种实现方式。
17+
这些实现在下文有详细的介绍,下表中先大概列举各种实现的区别:
18+
19+
技术 | Universal Link | Android App Link | URI Scheme | Chrome Intent
20+
--- | --- | --- | --- | ---
21+
平台要求 | >= iOS 9 | >= Android 6 | Chrome<sup>1</sup> < 25, iOS | Chrome<sup>1</sup> >= 25
22+
未安装表现 | 打开 Web 页面 | 打开 Web 页面 | 发生错误 | 可以打开 Web 页面
23+
能否不发生跳转 | 不能 | 不能 | 能 | 能
24+
能否去下载页面 | 能 | 能 | 不能 | 能
25+
iframe 触发 | 不支持 | 不支持 | Chrome<sup>1</sup> <= 18, iOS < 9 | 不支持
26+
链接格式 <sup>2</sup> | 正常的 URL | 正常的 URL | 自定义协议的 URL | intent 协议的 URL
27+
28+
1. 本文只针对移动端浏览器,其中 Chrome 表示 Chrome for Android,以及 Android Browser 的对应版本。
29+
2. 链接的作用方式有3中:用户点击这样的 `<a>` 标签;脚本中进行页面重定向;设置 `iframe``src`
30+
31+
## URI Scheme
32+
33+
URI Schema 是这几种调起方式中最原始的一种,协议名由 App 开发者命名。
34+
路径可以表示具体要打开的页面或功能。例如:
35+
36+
```html
37+
<a href="harttle://about"></a>
38+
```
39+
40+
URI Scheme 较为简单容易理解,但它的缺点也比较明显:
41+
42+
* 命名可能冲突。如果两款软件都叫 `harttle` 就会产生问题,因此这项技术是有设计缺陷的。
43+
* 调起失败时会直接发生错误,没有回调 URL。Android 和 iOS 都会弹框提示 URL 无效。
44+
45+
由于 iOS 下失败弹框不会阻塞,因此 [JavaScript 做 Fallback][uri-scheme-fallback] 可能会提前执行,体验会很糟糕。但相比于 Universal Link 调起失败后页面可以继续使用,也被广泛使用。比如京东的 Web 页面:
46+
47+
![ios uri scheme failed alert](/assets/img/blog/app/uri-scheme-not-installed-ios@2x.png)
48+
49+
在 Chrome for Android <= 18 以及 iOS < 9 的环境下可以避免上述错误弹框,
50+
通过设置 `iframe``src` 来触发 URI Scheme:
51+
52+
```html
53+
<iframe src="harttle://about"> </iframe>
54+
```
55+
56+
如果 APP 已安装,仍然需要用户点击确认才能跳转到 App。比如手机百度的跳转:
57+
58+
![ios uri scheme installed](/assets/img/blog/app/uri-scheme-installed-ios@2x.png)
59+
60+
## Universal Link
61+
62+
[Universal Link][universal-link] 是一个普通的,可以用任何浏览器打开的 Web URL。
63+
在 iOS >= 9 的系统中这些 URL 可以绑定到对应 App 中,如果安装有对应 App 就会调起,否则会直接打开该 URL。
64+
例如:
65+
66+
```html
67+
<a href="http://harttle.land/about.html"></a>
68+
```
69+
70+
Universal Link 通过 Web 服务器验证的方式避免了 URI Scheme 的命名冲突。
71+
只能通过页面跳转来触发,无法通过 `iframe` 触发,这意味着无论如何页面都要跳转。
72+
它的具体表现如下:
73+
74+
* 如果 App 未安装。会跳转至你给定的 Web 页面,这里可以导流到 iTunes,iOS 会负责启动 App Store。
75+
* 如果用户已安装,且这是第一次调起。会跳转至你给定的 Web 页面,下拉后 Safari 会显示打开 App 按钮(见下图)。
76+
* 如果用户已安装,且已经调起过。会直接打开 App。
77+
78+
![ios universal link first time](/assets/img/blog/app/universal-link-first-time@2x.jpeg)
79+
80+
> 需要服务器端给出 [`apple-app-site-association`][apple-app-site-association] 以验证 App 的 URL 绑定。
81+
82+
## Chrome Intent
83+
84+
在 Chrome for Android >= 25 的环境下,可以使用 [Chrome Intent][android-intent] 来调起 Android App。
85+
例如:
86+
87+
```html
88+
<a href="intent://about/#Intent;scheme=harttle;package=land.harttle;end"></a>
89+
```
90+
91+
相比于 URI Scheme,Chrome Intent 扩展了 `browser_fallback_url` 来定义未安装时的跳转链接。
92+
它的值是一个 [`encodeURIComponent`][encodeURIComponent] 过的 URL,例如:
93+
94+
```html
95+
<a href="intent://about/#Intent;scheme=harttle;package=land.harttle;S.browser_fallback_url=http%3A%2F%2Fharttle.land%2Fabout.html;end"></a>
96+
```
97+
98+
如果已安装,Chrome 会不询问用户直接调起 App。如果未安装,Chrome 会跳转至 `S.browser_fallback_url`
99+
100+
## Android App Link
101+
102+
类似 Universal Links,[Android App Link][android-app-links] 采取类似的机制:
103+
使用标准的 Web 页面 URL,同时绑定对应的 App。在 Android >=6 的系统中支持这一机制。
104+
例如下面的 URL:
105+
106+
```html
107+
<a href="http://harttle.land/about.html"></a>
108+
```
109+
110+
需要服务器端给出 `assetlinks.json` 以验证 App 的 URL 绑定。
111+
112+
## JavaScript 获取成功与否
113+
114+
上述所有调起方式都必须通过页面请求(除了特定情况下的 `iframe`),
115+
没有 JavaScript API 可用。理论上不存在调起结果回调。
116+
117+
但实践上可以通过 `setTimeout` 来检查页面是否还在运行,以及页面是否中断过。
118+
原理是如果页面切走(这意味着成功调起),`setTimeout` 回调的触发时间点会延迟。
119+
这一方式不够准确,但只有这一种办法。
120+
121+
* 如果被判定为调起成功,则一定是调起成功的。
122+
* 如果被判定为调起失败,则有可能调起成功。
123+
124+
即存在很大概率的 False Negative,但不存在 False Positive。
125+
126+
## 关于国产浏览器
127+
128+
这一部分讨论这三个浏览器的表现:UC, 微信,QQ。它们占据了系统浏览器之外的大多数市场份额,表现也惊人地一致。
129+
130+
* Android 下它们会拦截掉所有页面调起。需要提示用户从系统浏览器中打开。
131+
* iOS 下它们会拦截 URI Scheme,既不会弹框也不会调起。对于 Universal Link 会直接打开 Web 页面而不调起。
132+
133+
其中 UC 浏览器在 iOS <9 的环境下尝试 URI Scheme 调起很可能会直接崩溃。
134+
由于浏览器兼容性问题,以及 App 安装率不可能是 100%,调起成功率一般会很低尤其在 Android 下。
135+
136+
[deep-linking]: https://en.wikipedia.org/wiki/Deep_linking
137+
[uri-scheme-fallback]: https://blog.branch.io/uri-schemes-and-universal-links-for-ios/
138+
[universal-link]: https://developer.apple.com/ios/universal-links/
139+
[android-intent]: https://developer.chrome.com/multidevice/android/intents
140+
[encodeURIComponent]: /2017/05/23/percentage-encoding.html
141+
[android-app-links]: https://developer.android.com/training/app-links/index.html
142+
[apple-app-site-association]: https://developer.apple.com/library/content/documentation/General/Conceptual/AppSearch/UniversalLinks.html
246 KB
Loading
326 KB
Loading
466 KB
Loading

0 commit comments

Comments
 (0)