Apple 在 iOS9 加入的一个通用链接 (Universal Link) 的深度链接特性,这个特性让我们可以无缝的引导用户到 APP 上,在用户使用时有更好的体验。本文简单的介绍一下什么是通用链接?如何使用这个 iOS9 的特性。

什么是通用链接?

Apple 推出的通用链接:

一种能够方便的通过传统 HTTP 链接来启动 APP, 使用相同的网址打开网站和 APP。

通过唯一的 URL,不需要特殊的 schema 就可以链接一个指定的视图到 APP 里。比如:我们在淘宝中使用了通用链接,用户在 Safari、webView 等控件中点击一个链接,如果这个链接是在我们所指定通用链接内的,那么我们的 iOS 设备就会启动淘宝 APP 并且跳转的到指定的视图页面,如果没有安装则会在 Safari 中响应该链接。

集成通用链接三个步骤:

  • 创建一个包含 json 数据的 apple-app-site-association 文件
  • 把 apple-app-site-association 文件上传到服务器的根目录
  • 在 APP 里处理通用链接

与 URL Scheme 相比,两者都能唤醒 APP。URL Scheme 因为是自己定义的协议,所以在没有安装 APP 的情况下。无法直接打开。但是 Universal Link 就不同了。

  • Universal Link 本身是一个 HTTP/HTTPS 的链接。如果没有安装 APP,默认打开 safari,体验更加流畅
  • 不同的 APP 定义 URL Scheme,可能会出现冲突。当时 Universal Link 在 server 端维护一个 apple-app-site-association 文件。其中 appID 字段来标示 APP。就不存在上面的问题。
  • Universal Link 支持在 SFSafariViewController、UIWebView 和 WKWebView 跳转 APP
  • Universal Link 可以被搜索引擎索引。web 和 app 页面存在一个自定义的映射关系。

如何集成通用链接?

1. 创建一个 apple-app-site-association 文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{
"applinks": {
"apps": [],
"details": [
{
"appID": "9JA89QQLNQ.com.apple.wwdc",
"paths": [ "/wwdc/news/", "/videos/wwdc/2015/*" ]
},
{
"appID": "teamID.BundleID",
"paths": [ "*" ]
}
]
}
}

根据 json 数据中的 paths 字段来设定允许的路径,或者用 * 来表示任何路径都被允许,也就是我们可以使用任何链接打开 APP。

hint:paths 中路径是大小敏感的

其中 appID 字段的内容是 teamID + bundleID 来唯一确定 APP,中 teamID 需要在苹果开发者帐号中查看。bundleID 直接打开项目在 general 中查看。

2. 上传 apple-app-site-association 文件到服务器

需要注意的是 apple-app-site-association 文件要放在服务器的根目录下,并且该服务器是支持 HTTPS 的,不支持重定向,也就是说我们需要直接去访问 https://<domain>/apple-app-site-association 。通过这个 URL 我们发现对于 apple-app-site-association 文件我们不需要 .json 这样的后缀,虽然文件内包含的是 json 格式的数据。
一切都准备好了,我们就可以测试通用链接的特性了,在记事本或者短信中输入一个 URL 并点击如果跳转到你的 APP。那么就已经成功了。Apple 还提供了一个 网站 来检测通用链接是否可用。

3. 在 APP 里处理通用链接

在 APP 里处理通用链接,需要在 AppDelegate 里实现 application(_:continueUserActivity:restorationHandler:) 。很多其他功能的实现也是通过实现该代理方法,比如 spotlight 等。我们可以判断 userActivity 的 activityType 属性来确定是哪一种操作。

1
2
3
if userActivity.activityType == NSUserActivityTypeBrowsingWeb {
// coding to handle...
}

在该方法里路由 userActivity.webpageURL,也就是通过用户点击的链接来路由到指定的视图。

总结一下坑点

  1. 点击一个链接打开 APP 的之后 右上角出现一个箭头, 点击之后就会返回到 Safari 相应的页面。这里有个巨坑就是之后你会发现:你再点链接就不会跳转到 APP 了。这时候只有通过 3D Touch (6s 以上) 出现一个 ActionSheet,选择 在 "XXX" 中打开 ,之后点击链接就又可以跳转到 APP 了。这里 Apple 的设计猜想是兼顾到 safari 打开链接吧,点击了右上角的箭头代表了你不想跳转到 APP 所以下次就直接用 safari 打开了。换句话说,就是 Apple 会记住上次的操作。还有在配置 apple-app-site-association 文件的 paths 字段的时候不要太暴力的用 *,如果 route/a/*route/b/* 要比 route/* 要好。系统记住操作是根据 paths 来的。比如 route/a/* 用 safari 打开了,但是 route/b/* 这样的路径还是会跳转 APP,如果是 route/* 的话就一棒子打死了。
  2. safari 中是无法直接跳转到 APP 的。在 safari 输入一个链接之后,再下滑,会看到 在 “xxx” 应用中打开 这个一个 banner。点击跳转到 APP。如果你的页面会重定向到 H5 的话,记得将 domain 加入到 Associated Domains 中。
  3. universal links 要正常的在浏览器或者网页使用,是需要 跨域 的,也就是说 www.xxx.com/feed/1 这个 universal link 如果在 www.xxx.com 网页里点击是无法唤起 app 的,因为他们处于相同的域名之下。像知乎,airbnb,就是用一个子域名专门来制作 universal link 。eg:ois.zhihu.com 当然对应的 apple-app-site-association 和 Xcode 中的 Applinks 也要做相应的修改。

总结

上面所提及到的通用链接是深度链接(deep link)的一种表现形式,其基本的思想就是系统通过拦截和解析 HOST 地址,与系统注册的 HOST 进行匹配,如果发现就可以直接打开APP,之后的 URL 路由问题由 AppDelegate 代理方法来完成。
对于现在移动互联网时代,搜索引擎是无法搜索到 APP 内容数据,因此搜索引擎公司希望能够建立 web 和 APP 之间的关系索引,对于百度/google 等提供技术支持和相应的接口,让 APP 开发者提交 Web 和 APP 的映射关系。这样移动用户可以直接打开 APP,提交用户体验。

值得注意的是对于 apple-app-site-association 文件的 json 数据中的 paths 字段有许多规则:

  • “NOT /videos/wwdc/2010/*” 不处理含有 videos/wwdc/2010 前缀的路径
  • “/videos/wwdc/201?/*” 用 ? 来表示任意的单个字符

参考

iOS9: Universal Links does not work
Deferred Deep Linking in iOS
Apple:Support Universal Links