当你支持通用链接(Universal Links)时,iOS 用户可以点击你网站的链接并无缝重定向到你已安装的 App 中,而无需通过 Safari 跳转。如果你的 App 尚未安装,点击你网站的链接将在 Safari 中正常打开你的网站。

与使用自定义 URL Schemes 相比,通用链接为你提供了几个无法比拟的关键优势。具体而言,通用链接具有以下特点:

  • 唯一性。 与自定义 URL Schemes 不同,通用链接不能被其他 App 抢占使用,因为它们使用的是指向你网站的标准 HTTP 或 HTTPS 链接。
  • 安全性。 当用户安装你的 App 时,iOS 会检查你上传到 Web 服务器的一个配置文件,以确保你的网站允许你的 App 代表它打开相关的 URL。只有你能够创建和上传此文件,因此你的网站与 App 之间的关联是绝对安全的。
  • 灵活性。 即使你的 App 尚未安装,通用链接也能正常工作。当你的 App 未安装时,点击指向你网站的链接会在 Safari 中打开对应的内容,这完全符合用户的预期。
  • 简单性。 同一个 URL 可以同时适用于你的网站和 App。
  • 隐私性。 其他 App 可以在不需要知道你的 App 是否已安装的情况下,通过通用链接与你的 App 进行通信。

注意
通用链接不仅允许用户在点击 Mail、Messages 或其他 App 中的链接(这些链接通常会调用 openURL:)时打开你的 App,还允许用户在 Safari 以及 WKWebViewUIWebView 视图内点击你网站的链接时打开你的 App。
当用户在 Safari 中浏览你的网站并点击了一个与当前网页属于相同域名的通用链接时,iOS 会尊重用户最可能的意图,并在 Safari 中打开该链接。如果用户点击了指向不同域名的通用链接,iOS 就会在你的 App 中打开该链接。
对于运行低于 iOS 9.0 版本的用户,点击你网站的通用链接只会在 Safari 中打开。

添加对通用链接的支持非常简单。你需要采取以下三个步骤:

  1. 创建一个 apple-app-site-association 文件,该文件包含有关你的 App 可以处理哪些 URL 的 JSON 数据。
  2. apple-app-site-association 文件上传到你的 HTTPS Web 服务器。你可以将文件放置在服务器的根目录或 .well-known 子目录中。
  3. 准备你的 App 以处理这些通用链接。

你可以在真实设备上测试通用链接的功能。


创建并上传关联文件 (Creating and Uploading the Association File)

为了在你的网站和 App 之间创建安全连接,你需要在它们之间建立信任关系。你可以通过以下两部分建立这种关系:

  • 添加到你网站的 apple-app-site-association 文件。
  • 添加到你 App 的 com.apple.developer.associated-domains 授权(这将在后续部分详细描述)。

注意
如果你的 App 运行在 iOS 9 或更高版本中,并且你使用 HTTPS 提供 apple-app-site-association 文件,你可以创建一个使用 application/json MIME 类型的纯文本文件,并且不需要对其进行签名。如果你需要支持 iOS 8 中的 Handoff 和 Shared Web Credentials,你仍然需要对该文件进行签名。

你需要为你 App 支持的每个包含独特内容的域名提供一个单独的 apple-app-site-association 文件。例如,apple.comdeveloper.apple.com 需要单独的文件,因为它们提供不同的内容。相反,apple.comwww.apple.com 不需要单独的文件(因为这两个域名通常提供相同的内容),但这两个域名都必须确保该文件可被访问。对于在 iOS 9.3.1 及更高版本中运行的 App,apple-app-site-association 文件的未压缩大小不得超过 128 KB。

在你的 apple-app-site-association 文件中,你可以指定网站上哪些路径应作为通用链接处理,以及哪些路径不应作为通用链接处理。尽量保持路径列表简短,并依赖通配符匹配来涵盖更大的路径集合。

代码清单:创建 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": "ABCD1234.com.apple.wwdc",
"paths": [ "*" ]
}
]
}
}

注意
请勿在 apple-app-site-association 文件名后附加 .json 后缀。

apple-app-site-association 文件中的 apps 键必须存在,且其值必须为空数组。details 键的值是一个字典数组,每个字典对应你的网站支持的一个 App。数组中字典的顺序决定了系统寻找匹配项时的顺序。

每个特定于 App 的字典包含一个 appID 键和一个 paths 键。appID 键的值是 Team ID 或 App ID 前缀,后跟 Bundle ID。paths 键的值是一个字符串数组,指定了该 App 支持的网站路径以及不想与该 App 关联的网站路径。要指定不应作为通用链接处理的区域,请在路径字符串的开头添加 "NOT "(注意 T 后面有一个空格)。例如,你可以通过以下方式阻止 /videos/wwdc/2010/* 被作为通用链接处理:

1
"paths": [ "/wwdc/news/", "NOT /videos/wwdc/2010/*", "/videos/wwdc/201?/*"]

由于系统按指定的顺序评估 paths 数组中的每个路径(一旦找到肯定或否定的匹配项就会停止评估),因此你应该将高优先级路径放在低优先级路径之前。请注意,系统仅使用 URL 的路径组件进行比较。其他组件(如查询字符串或片段标识符)将被忽略。

你可以使用多种方式指定路径:

  • 使用 * 指定整个网站。
  • 包含特定 URL,如 /wwdc/news/
  • 在特定 URL 后附加 *,如 /videos/wwdc/2015/*
  • 使用 ? 匹配任何单个字符,例如 /foo/*/bar/201?/mypage

注意
paths 数组中用于指定网站路径的字符串是区分大小写的。

创建文件后,将其上传到你的 HTTPS Web 服务器的根目录或 .well-known 子目录中。该文件需要能够通过 HTTPS 无重定向地访问:https://<domain>/apple-app-site-associationhttps://<domain>/.well-known/apple-app-site-association


通用链接主要使用两种技术:Handoff 机制和 Shared Web Credentials。当用户点击通用链接时,iOS 会启动你的 App 并向其发送一个 NSUserActivity 对象,你可以查询该对象以了解 App 是如何被启动的。

要在你的 App 中支持通用链接,请执行以下步骤:

  1. 添加一个授权 (Entitlement),指定你的 App 支持的域名。
  2. 更新你的 App Delegate,以便在接收到 NSUserActivity 对象时做出适当的响应。

在你的 com.apple.developer.associated-domains 授权中,包含你的 App 想要作为通用链接处理的域名列表。在 Xcode 中,打开 Capabilities 选项卡下的 Associated Domains 部分,并为每个支持的域名添加一个带有 applinks: 前缀的条目,例如 applinks:www.mywebsite.com。建议将此列表限制在不超过 20 到 30 个域。

要匹配关联域的所有子域,可以通过在特定域前添加 *. 前缀(必须包含点)。系统根据 applinks 条目中最长的子字符串进行域匹配。

指定关联域后,采用用于 Handoff 的 UIApplicationDelegate 方法(具体来说是 application:continueUserActivity:restorationHandler:),以便你的 App 能够接收并正确处理链接。

当 iOS 在用户点击通用链接后启动你的 App 时,你会收到一个 NSUserActivity 对象,其 activityType 值为 NSUserActivityTypeBrowsingWeb。该活动对象的 webpageURL 属性包含用户正在访问的 URL。你可以使用 NSURLComponents API 来解析和操作 URL 的各个部分。

注意
如果你实例化了一个 SFSafariViewControllerWKWebViewUIWebView 对象来处理通用链接,iOS 会在 Safari 中打开你的网站而不是打开你的 App。但是,如果用户在嵌入的 SFSafariViewControllerWKWebViewUIWebView 视图内部点击了通用链接,iOS 则会打开你的 App。

需要了解的一点是,如果你的 App 使用 openURL: 打开指向你网站的通用链接,该链接不会在你的 App 中打开。在这种情况下,iOS 识别到调用源自你的 App,因此不会将其作为通用链接处理。

如果在活动对象中收到无效或不支持的 URL,为了优雅地处理,你可以在 shared application 对象上调用 openURL: 在 Safari 中打开该链接。如果无法进行此调用,请向用户显示一条错误消息解释出了什么问题。

重要提示
为了保护用户的隐私和安全,在需要传输数据时绝不要使用 HTTP;相反,应始终使用安全的传输协议,例如 HTTPS。