iOS Universal Links & URL Scheme

最近我们有一个 DeepLink 的需求 用的是 Branch, 在这个过程中自然会涉及到 Universal Links 和 Custom URL Schem,在此进行笔记下,也把在用 Branch 中遇到的问题分享下。

// Respond to URI scheme links
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {
   // 我们需要的判断跳转
   return YES;
}

// Respond to Universal Links
- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void (^)(NSArray *restorableObjects))restorationHandler { 
  // 我们需要的判断跳转
   return YES;
}

然后从下面四个点来了解下这块:

  • Universal Links 和 URL Schem 基本概念的了解
  • Universal Links 和 URL Schem 的用法
  • Universal Links 和 URL Schem 需要的注意点
  • Branch 使用中遇到的问题

一、基本了解

  • URL Scheme
    URL Scheme 是为方便app之间互相调用而设计的,注册自己独一的URL Scheme,然后进行交互。我们可以通过系统的OpenURL来打开该app,也可以直接通过 Safari 直接打开该 app,并可以传递参数内容。
  • Universal Links
    iOS 9 之后,苹果推出的通用链接:一种能够方便的通过传统 HTTP 链接来启动 APP, 使用相同的网址打开网站和 APP。
    推出它,肯定有其优点:
  • 唯一性: 不像自定义的scheme,因为它使用标准的http/https链接到你的web站点,所以它不会被其它的app所声明.另外,Custom URL scheme 因为是自定义的协议,所以在没有安装 app 的情况下是无法直接打开的,而 universal links 本身是一个 HTTP/HTTPS 链接,所以有更好的兼容性
  • 安全:当用户的手机上安装了你的app,那么iOS将去你的网站上去下载你上传上去的说明文件(这个说明文件声明了你的app可以打开哪些类型的http链接).因为只有你自己才能上传文件到你网站的根目录,所以你的网站和你的app之间的关联是安全的.
  • 可变:当用户手机上没有安装你的app的时候,Universal Links也能够工作.如果你愿意,在没有安装你的app的时候,用户点击链接,会在safari中展示你网站的内容.
  • 简单:一个URL链接,可以同时作用于网站和app
  • 私有 其它app可以在不需要知道你的app是否安装了的情况下和你的app相互通信.

二、用法

两者代码里面其实没什么区别,主要是配置的去呗

2-1、URL Scheme
  • 2-1-1、注册设置 URL Scheme


    iOS Universal Links & URL Scheme_第1张图片
    注册设置 URL Scheme
  • 2-1-2、AppDelegate 设置

   - (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL*)url {
    // 接受传过来的参数
    NSLog(@"url Scheme === %@\n url Host === %@",url.scheme,url.host);
    // url Scheme === testyang  url Host === testContent
    return YES;
}
  • 2-1-3、打开
    • Safari


      iOS Universal Links & URL Scheme_第2张图片
      Safari 输入

      iOS Universal Links & URL Scheme_第3张图片
      弹出提示框,TestUrlScheme 是 app 名字
    • App 之间
      在另一个 App 中的 info Plist 中添加白名单 Url

   LSApplicationQueriesSchemes
    
        
        testYang
    

在另一个 APP 中 添加打开的 代码

    NSString *url = @"testYang://testContent";
//    NSString *url = @"testYang://com.testYang.www&testContent";
    if ([[UIApplication sharedApplication]
         canOpenURL:[NSURL URLWithString:url]]) {
        // iOS 10 以上用这个方法,iOS 10 以下直接用 openURL 就 OK 了
        [[UIApplication sharedApplication] openURL:[NSURL URLWithString:url] options:@{UIApplicationOpenURLOptionUniversalLinksOnly : @NO}  completionHandler:^(BOOL success) {
            NSLog(@"success");
        }];
    }

注意:APP URL格式为: URL Scheme://URL identifier,直接调用URL Scheme也可打开程序, URL identifier是可选的。

2-2、Universal Links
  • 2-2-1、创建一个json 格式的apple-app-site-association
{
    "applinks": {
        "apps": [],
        "details": [
            {
                "appID": "9JA89QQLNQ.com.apple.wwdc",
                "paths": [ "/wwdc/news/", "/videos/wwdc/2015/*"]
            },
            {
                "appID": "ABCD1234.com.apple.wwdc",
                "paths": [ "*" ]
            }
        ]
    }
}
  *  “appID”组成部分:TeamID + BundleId TeamID
  *  BundleId 一定要和 APP 的 BundleId 一致。
  * apple-app-site-association 文件不能带后缀
  * apple-app-site-association 文件需要上传到网站根目录
  *  每一个代表着应用的 字典,必须包含一个 appID 和 paths, appID 是teamID 和 bundleID,paths 是一个字符串的数组 **明确着应用支持的通用链接和应用程序不支持的通用连接内容**

Note: Don’t append .json to the apple-app-site-association
filename. (文件不要接 .json)

  • 2-2-2、上传 apple-app-site-association 到服务器下

    • 注意是上传到web server根目录下
    • paths 路径是大小写敏感的
    • paths 内容可明确哪些通用链接需要被处理,哪些不需要
    • NOT 使用:为了明确指出不被处理的链接,可增加 “NOT”在链接前面
      例 如 "paths": [ "/wwdc/news/", "NOT /videos/wwdc/2015/*", "/videos/wwdc/201?/*"]
    • 可以使用 星号* 明确所有的网页, 也可以使用一个明确的的 URL,例如 /wwdc/news/6, 也可以追加 星号到你的 URL ,例如/videos/wwdc/2015/* 也可以使用 星号
      * 来匹配任何字符,使用 ? 来匹配一个字符,可以在路径 中使用这种混搭的形式, 例如 /foo/*/bar/201?/mypage
  • 2-2-3、App 内的处理

    • 2-2-3-1、在targets->Capabilities->Associated Domains中打开Associated,然后系统会自动帮你写入.entitlements文件,所以不需要自己去手动加。需要注意的是,有人遇到过.entitlements文件没有被加入工程的,这也会产生问题,需要手动把.entitlements加入工程。


      iOS Universal Links & URL Scheme_第4张图片
      打开Associated
    • 2-2-3-2、代码内的处理 AppDelegate 中
      - (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void (^)(NSArray *restorableObjects))restorationHandler { 
        // 我们需要的判断跳转
         return YES;
}
  • 2-2-3-4、在 证书中心的处理
    进入苹果Apple Developer --- Member Center - Certificates, Identifiers & Profiles – Identifiers - App IDs –Edit 然后开启打钩 Associated Domains 后保存,但此处我这边自动成了。
    Associated Domains

    如有不清晰,可以再看这个翻译iOS Universal Links(通用链接)还是很仔细的。

三、注意点

  • URL Scheme
    • URL identifier 的唯一性
    • iOS9 之后的白名单
    • iOS 10 之后的 OpenURL 的被弃用
  • Universal Links
    • 域名可通过 SSL 访问 (需要有效的证书)
    • 支持上传一个 JSON 文件到域名(apple-app-site-association
    • iPhone 至少 iOS 9.2 以上
    • 至少 Xcode 7 以上
    • 需要真机测试, 模拟器不支持通用链接
    • web server 需要支持 https,客户端需要通告 https 访问,并且不支持任何重定向

总的说来,URL Scheme慢慢会退出舞台,然后是Universal Links 登上台面的时候。PS: 苹果验证Universal Links URL 是否正确的网址。

四、Branch DeepLink 使用中遇到的问题

作为国外常用的 Branch,国内目前基本应该不太用的,整体说来其文档相对来说,还是很清晰的,只是之前一直有两点困扰我的:

  • 如何自定义类型做判断跳转
  • 一直跳转不成功,设置好URL ,始终从Web 页面跳转不到 APP, 只往AppStore 走

  • 1、如何自定义类型做判断跳转,因为它不同于系统的,直接在 openURL中做判断,而是先要用其SDK 提供的方法。

  - (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {
     [[Branch getInstance] handleDeepLink:url];
      return YES;
}
  - (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void (^)(NSArray *restorableObjects))restorationHandler {
     BOOL handledByBranch = [[Branch getInstance] continueUserActivity:userActivity]; 
     return handledByBranch;
}

但这是第一层,以前我们判断就是拿到这个 url 就是直接去判断,然后跳转到我们想走的跳转路线,但是此处呢?

 [branch initSessionWithLaunchOptions:launchOptions andRegisterDeepLinkHandler:^(NSDictionary *params, NSError *error) {
    if (!error && params) {
        NSLog(@"params: %@", params.description);
        if ([params[@"+clicked_branch_link"] boolValue]) { // 此处代表是 branch_link 点击进入的情况
             [DeepLinkManager branchDeepLinkWithParams:params];
           }
       }
 }];
  • 2、一直跳转不成功,设置好URL ,始终从Web 页面跳转不到 APP, 只往 AppStore 走。
    注意 Branch 文档中的 Link Domain 设置 Associated Domains 错误啦。
    而且通过 branch 的测试 URL 是满足条件的 UNIVERSAL LINKS VALIDATOR。但是在苹果验证Universal Links URL 是否正确的网址上却是错误的:
    **cannot fetch app site association **
    iOS Universal Links & URL Scheme_第5张图片
    cannot fetch app site association

    这就尴尬了,branch 处是OK的,apple 提示Universal Links是错误的。但同时也说明 URL Scheme 设置是对的,否则会单单直接报出一个 “Error: cannot fetch app site association ” 的错误。

所以说,此时的问题又回归到 Universal Links 没设置对的原因,没能正确上传好app site association,但是此处使用的是 Branch, 这个设置 Universal Links 就是按 Branch 流程 上面走的,这样就略显尴尬啦,一下子原因找不到,卡了好久。

解决步骤1:https://domian.com/apple-app-site-association 看是否正确,当然用 Branch 的话是https://domian.app.link/apple-app-site-association, 结果发现这是存在的,但是内容有点不一样 path

"paths": [
                    "NOT /e/*",
                    "*",
                    "/"
                ]

然后我对比了下经典的例子收集 list-of-universal-link,继续寻找中...

解决步骤2: 直接向 branch 邮箱求助,那边的工作人员会给出很详细的解答步骤,第一次没有解决,现在等待第二次邮件回复...

解决步骤3: 硬是不行,再重新弄一个账号尝试,对比过程是否有遗漏的东东...

PS: 最终解决:
通过邮件得知,苹果那边的那个验证没有通过其实也是OK的, 所以那里可以忽略。
只是之前设置的时候,设置错误了..
注意 branch_key 直接设置,注意 test 和 live 的区别,但是其实可以直接 不用 dictionary, 而用 string, 因为我暂时设置成 Debug 状态下有时是无效的,所以直接用string ,到时替换就好了。

Dictionary
String

另外出现这个问题也可以看看 Stack Overflow 的回答:iOS9: Universal Links does not work。

话说起来这也是一个自己熟悉陌生英文文档的过程,可以多来几次,这一两天全是英文文档感觉英语都提高了,,只是希望下次效率可以更高一些。说白了,所有问题都是文档没弄清晰的原因。

PS : 再次补充:

有些情况下,在 FaceBook、 QQ、微博 用的是本身的浏览器,都有其限制的,此时我们直接用 DeepView , 方能解决,否则会一直跳转到 AppStore 去的。

五、总结

其实总的来说,想了解更详细的直接看苹果官方文档就OK 了。

  • Support Universal Links
  • URL Scheme

往往出错是在看文档的时候忽略一些细节!明显是在就是翻译文档,,但还翻译错了,或者说理解错了......

备注:

URL Scheme步骤详解
Using URL Schemes to Communicate with Apps
Support Universal Links
ios-branch-deep-linking
iOS 9 by Tutorials 笔记(三)
Deferred Deep Linking in iOS
iOS Universal Links(通用链接)

你可能感兴趣的:(iOS Universal Links & URL Scheme)