iOS Collection

iOS 13.0 通用链接新功能 Universal Links

2020-05-06  本文已影响0人  沐灵洛

概念

通用链接Universal Links :是HTTPHTTPSURLs(统一资源定位符),Apple的操作系统会将这些URL识别 为指向网络或App中的资源。无论是在网上还是在App中,这意味着无论用户是否下载安装了我们的App,此URL都可以表示该内容。

iOS 9.0中引入了通用链接,通用链接在我们的App和网站之间是安全关联的。AppXcode中采用了一个权限,来指示该App通用链接涉及哪些域。
我们的WEB服务器采用了一个JSON文件,该文件描述了我们App,也描述了如何过滤域对应的URL,使得我们期望的URL可以在App中打开。这种双向安全握手确保没有人可以将用户重定向到其他的App而不是我们的App

关于使用苹果强烈建议使用通用链接代替之前自定义的URL schemes。因为自定义的URL schemes的方式本质上是不安全的,可能被恶意开发人员滥用。

配置

配置WEB服务器

WEB服务器必须有一个有效的HTTPS证书。HTTP不安全,不能用于验证App和网站之间的关联。用于签名HTTPS的根证书必须被操作系统识别,不支持自定义的根证书。生成证书并配置服务器之后,需要添加Apple-app-site-association文件,这是一个JSON文件,文件的格式我们稍后讨论。当我们App安装在苹果的设备上时,苹果的操作系统将会下载该文件,以确定服务器允许我们的App使用那些服务。系统还会定期下载此文件的更新。通用链接是这个文件中可能包含的众多服务之一。

通用链接示例:https://example.com/.well-known/Apple-app-site-association
Apple-app-site-association这个文件应该位于我们的域名example.com/.well-known下并且苹果不推荐使用其他路径。
过去,苹果讨论过对Apple-app-site-association这个文件是否签名,觉得签名从来不是支持普遍联系的必要步骤,所以被弃用了,因此可以不用对Apple-app-site-association这个文件签名啦。支持已签名的文件,处在其他路径的JSON文件将在将来的版本中取消对其的支持。

Apple-app-site-association文件格式:

顶层字典其KEY是服务类型,对于通用链接,KEYapplink,但是也可以使用其他服务的关键字。聚焦于通用链接,在applink下面的KEYapps,details

apps:如果是在iOS 13上我们是不需要apps的,所以可以删除。如果对于iOS 13以前的版本需要继续提供支持,则仍然需要保留apps。对于通用链接来说apps应该总是一个空数组。

detailsdetails键对应的值是一个包含字典类型的数组,每个字典代表一个特定App的通用链接配置。过去此处我们支持使用字典结构,而不是数组结构,但是这种配置方式已经过时了。

details键下面的appID对应的值是我们的App标识符。我们的App标识符由Apple提供的字母数字(10个字符)前缀和AppbundleId组成。前缀可能等于也可能不等于我们的团队标识符,检查Apple developer门户网站确认App标识符。如果我们的App具有多个相同通用链接配置,我们可能不想重复关联JSON文件,若是iOS 13,则可以使用appIDs键,来减少该文件的大小。appIDs键的值是一个App标识符数组。

若需要支持以前的版本,则应该继续为每个App使用单一的appID键。

details键下面的paths键对应的值是路径模式数组。模式匹配与在终端中执行方式相同。*表示通配符,?匹配一个字符。

2019年也就是iOS 13开始,苹果用components键替换了paths键。components键的值是一个字典数组,每个字典称为一组URL的匹配模式,也称为一个组件,每个组件都包含零个或多个匹配URL不同组成部分语句,来模式匹配URL。与先前路径模式数组一样组件也可以匹配URL的路径。在组件中匹配URLpath部分的键是"/",值(示例)为:/path/*/filename。如果需要支持以前的版本可以保留paths键,在iOS 13中如果components键存在将忽略paths键。
新增匹配项:
每个组件新增匹配URLFragment部分,在组件中匹配URLFragment部分的键是"#",值(示例)为:"*fragment"
每个组件新增匹配URLQuery部分,在组件中匹配URLQuery部分的键是"?",值(示例)为:"*widget=?*"或指定为字典:{"widget":"?*","grommet":"please"}

要使组件字典匹配候选的URL,则组件中的匹配项都必须匹配。如果不指定组件某个匹配项:路径,Fragment等,操作系统默认行为便是忽略匹配URL对应的那一部分。例如我们的App不关心URLFragment则不需要在组件中指定Fragment的模式匹配项。我们的网站可能有一些部分,还不能在App中显示,我们可以在组件中通过指定exclude键对应的的布尔值为true来排除这些子部分,此组件匹配到的URL将不会作为通用链接在App中打开。此键具有与在旧的paths键中使用Not关键字相同的行为,在使用组件字典时,不支持Not关键字。
这里有一些URL使用组件进行模式匹配的例子:

注意点:

  1. URL必须始终使用ASCII编码,组件模式匹配也是用ASCII码完成的。
  2. 国际化时为减少Apple-app-site-association文件的下载大小,可以使用更灵活的匹配方式。
  3. 操作系统会根据用户最可能浏览的位置(域)对Apple-app-site-association文件下载进行优先级排序。虽然在安装App时都会下载它们,但是优先级不同,顶级域名.com.net.org是高优先级的域,因为用户流量大。还有用户的ccTLD(国家代码TLD),若国际化的TLD与用户当前语言环境匹配,也会被优先下载。

配置App

Xcode 13中导航到Signning&Capabilities添加Associated Domains功能。

处理通用链接

激活通用链接,iOS将启动App并且向它发送NSUserActivity对象。我们需要解析这个对象,确定启动方式,决定如何处理。

当iOS通过通用链接打开我们的应用程序时,应用程序会收到一个NSUserActivity对象,其属性activityType值为NSUserActivityTypeBrowsingWeb。对象的webpageURL属性包含用户访问的HTTPHTTPS URL。使用NSURLComponents 提取URL的组件。

//https://dev-api.yidux.cn/path/wally/test?name=Wally&age=1
func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
    guard userActivity.activityType == NSUserActivityTypeBrowsingWeb,
        let webpageUrl = userActivity.webpageURL,
        let components = NSURLComponents.init(url: webpageUrl, resolvingAgainstBaseURL: true),
        let path = components.path
        else {
        return false
    }
    
    print("URL是\(webpageUrl.absoluteString),URL的组件:\(components)")
    print("PATH:\(path)")
    print("QUERY:\(String(describing: components.queryItems))")
    if let queryItems = components.queryItems , let name = queryItems.first(where: {$0.name == "name"})?.value, let age = queryItems.first(where: {$0.name == "age"})?.value {
        print("QUERY部分,name = \(name),age = \(age)")
    }
    
    return true
}
上一篇下一篇

猜你喜欢

热点阅读