美文网首页iOS Collection
iOS 13.0 通用链接新功能 Universal Links

iOS 13.0 通用链接新功能 Universal Links

作者: 沐灵洛 | 来源:发表于2020-05-06 22:59 被阅读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对象。我们需要解析这个对象,确定启动方式,决定如何处理。

    • 在您的应用程序和网站之间创建双向关联,并指定应用程序处理的URL

    • App收到NSUserActivity对象并且对象的属性ActivityTypeNSUserActivityTypeBrowsingWeb时,及时做出响应。

    当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
    }
    

    相关文章

      网友评论

        本文标题:iOS 13.0 通用链接新功能 Universal Links

        本文链接:https://www.haomeiwen.com/subject/sraductx.html