入秋了,路上会遇到用小贩用小货车拉着卖芒果,和去年一样,我会停下急匆匆的脚步,买几个。一则自己爱吃芒果不过敏,二则品尝下是否和去年一样熟悉的味道。
很多时候可能都希望在浏览器,微信里面点击一个H5链接或按钮,之后直接打开App跳到App里面指定的页面。

预期效果

safari,chrome,UC,搜狗,opera Mini等浏览器——-》唤醒App

用户通过浏览器地址栏输入官网地址,或商品地址打开App里面指定页面。若手机内未安装App则引导用户跳入Apple Store下载页。(本来准备举美团的例子,结果美团变成了小程序,那就某东吧)。
在浏览器中输入商品地址:

手机安装了某东

achwi-ukqeu.gif

手机未安装某东

aewsx-la7td.gif

微信,QQ,微博——-》唤醒APP

用户通过某APP分享了一条链接至微信,QQ或微博,用户点开该链接后,会引导用户B打开该APP或者下载该APP
在微信里面点击的分享的商品

手机安装了某东

afjby-jit4x.gif

手机未安装某东

a8umw-pkv2a.gif

短信、备忘录,邮件——-> 唤醒APP

用户收到一条推广短信,在短信里面点击链接跳入App里面或下载App页

如何实现上面的场景呢?分为iOS9.0以前和iOS9.0以后。

实现方式

scheme方式

iOS9.0以前只有一种实现方式
若安装App则跳入指定页面,则scheme后面加参数:”taobao://item.taobao.com/item.htm?id=“。若未安装跳到下载页引导用户下载安装

  1. let link = "taobao://item.taobao.com/item.htm?id=" + id,
  2. fallback = "itms-apps://itunes.apple.com/cn/app/" + appId;
  3. // 尝试呼起 App
  4. location.href = link;
  5. // 3s 后未能呼起则跳转 App Store
  6. setTimeout(() => location.href = fallback, 3000);

浏览器如何知道手机是否安装了App呢,通过设置延时。

setTimeout的实现过程

浏览器尝试打开URL scheme并记录时间点t1,在2秒计时后,检查当前时间t2,如果t2-t1 > 2200ms,说明唤起app成功(唤起app会是浏览器的定时器延后执行),如果t2-t1 < 2200ms,可能没有安装app,可以引导用户进入下载页。
az81a-50cnd.gif
a593c-a6r7f.gif

  1. var openTime = +new Date();
  2. window.location.href = 'wzry://videolists.show/mark/penta_kill?num=1'
  3. var timer = setTimeout(function () {
  4. if ((new Date()) - openTime < 2200) {//加了200ms基准误差
  5. window.location.href = 'you app download page';
  6. }
  7. if ((new Date()) - openTime > 2200) {
  8. clearTimeout(timer);
  9. }
  10. }, 2000);

setInterval实现过程

原理上跟setTimeout相似,方法上换成设置一个比较小的时间间隔(例如20ms),运行多次(例如100),比较运行完
100次的总耗时与20*100的时间差。逻辑判断同setTimeout

  1. var limit_num = 100;
  2. var openTime = +new Date();
  3. window.location.href = 'wzry://videolists.show/mark/penta_kill?num=1'
  4. var timer = setInterval(function () {
  5. if(limit_num > 0){
  6. limit_num--;
  7. }else{
  8. if ((new Date()) - openTime < 2200) {//加了200ms基准误差
  9. window.location.href = 'you app download page';
  10. }
  11. clearTimeout(timer);
  12. }
  13. }, 20);

重要的事情说三遍,iOS9.0以后还是可以用scheme,只是在iOS9上,iframe方案变得不可用,在打开自定义URL scheme时,会弹出对话框,询问是否用 xx应用来打开。若未安装App则会显示“safari打不开该网页,因为网址无效”。(可以通过直接跳转:点击链接或者修改window.location。唤醒你的APP,window.location.href = schemeUrl)

针对微信

就不区分iOS9.0之前和之后了,因为微信有白名单,白名单里面只包含50个App的url scheme。怎么查看呢。通过Apple configuration 2能够查到,具体请看文章
白名单如下:在这个 plist 文件中找到白名单很简单,因为微信已经达到了49个的上限,一个很扎眼的 “(49 items)” 的 “Array” 项 LSApplicationQueriesSchemes 就是我们要找的白名单了。我们可以看到诸如腾讯新闻 (qqnews), 腾讯视频 (tenvideo2) 都是在白名单内的
image.png

从微信里面打开分享的网页跳入App

使用腾讯应用宝

使用它颁发给你的应用地址,向这个地址跳转,然后一切就交给微信了,直接无视微信什么的,直接带你飞到app内。具体可看腾讯应用宝Applink接入文档。举个例子,网易新闻。从网易新闻分享一天链接到微信,在微信里面点开链接

若安装了微信。直接打开到网易新闻App对应链接

azkqa-oxkhr.gif
axu1h-omn28.gif
a596c-1bnqf.gif

Universal Links(通用链接)

优点

  • 唯一性:不像自定义的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,可以定义统一的web-native协议;
  • 私有:其它APP可以在不需要知道是否安装了的情况下和你的APP相互通信;

    缺点

    只支持iOS9及以上系统;当使用Universal Link打开APP之后,状态栏右上角会出现链接地址,点击它会取消Universal Link,需引导用户重新使用Safari再次打开该链接,弹出Safari内置APP广告条,再点击打开重新开启Universal Link

    实现

    本来一般公司会有一个官网域名https://www.aaaaa.com/,你必须找运维同学开一个专门用来制作通用链接的域名https://oap.aaaaa.com,然后上传apple-app-site-association的json文件到.well-known和根目录,具体如下面的步骤:

    1.创建一个json格式的命名为apple-app-site-association文件,注意这个文件必须没有后缀名,文件名必须为apple-app-site-association上传到https.

    1. {
    2. "applinks": {
    3. "apps": [],
    4. "details": [
    5. {
    6. "appID": "ABCD1234.com.aaa.app",
    7. "paths": [ "/info/*", "/mobile/*"]
    8. },
    9. {
    10. "appID": "EFGH5678.com.bbb.app",
    11. "paths": [ "*" ]
    12. }
    13. ]
    14. }
    15. }
    说明: appID = teamId.yourapp’s bundle identifier
    paths = APP支持的路径列表,只有这些指定的路径的链接,才能被APP所处理,大小写敏感。举个例子,如果你的网站是oap.aaa.com,你的path写的是”/info/*”,那么当用户点击www.aaa.com/info/?=,就可以唤醒APP了,相反www.aaa.com/other就不会。此外Apple为了方便开发者,提供了一个网址来验证我们编写的这个apple-app-site-association是否合法有效,这个网址经过测试后有的有效果有的没有效果。下图是输入oia.zhihu.com之后的效果。
    image.png

    2.激活Xcode工程中的Associated Domains能力,在其中的Domains中填入你想支持的域名(这里不是随便填的,是可以支持你需要的Universal Links的域名), 必须以applinks:为前缀,例如:applinks:oap.aaaaa.com将会在合适的时候,从这个域名请求apple-app-site-association文件。注意:当你打开Associated Domains后,Xcode会在你的工程中添加.entitlements文件,并且登录开发者中心,可以看到Associated Domains处于Enable状态。

image.png

3.在AppDelegate里实现如下代理方法:

  1. - (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void (^)(NSArray *))restorationHandler {
  2. // NSUserActivityTypeBrowsingWeb 由Universal Links唤醒的APP
  3. if ([userActivity.activityType isEqualToString:NSUserActivityTypeBrowsingWeb]) {
  4. NSURL *webpageURL = userActivity.webpageURL;
  5. NSString *host = webpageURL.host;
  6. if ([host isEqualToString:@"yohunl.com"]) {
  7. //进行我们需要的处理
  8. } else {
  9. [[UIApplication sharedApplication]openURL:webpageURL];
  10. }
  11. }
  12. return YES;
  13. }

至此APP已经开启Universal Links,可以通过链接唤醒APP,并跳转至指定页面了。流程如下:

image.png

4.跨域。假设当前微信浏览器中话题详情页面的 URL 为 “www.domain.com/XXX“,底部“打开App”按钮对应的链接URL为 “www.domain.com/YYY“,但由于www.domain.com/YYY不在配置的域名oap.domain.com的域名下,因此实际不能完成跳转。必须写点击事件跳转到与applinks中添加的域名相同的页面例如oap.aaaaa.com/info/download.html(要跨域),在微信中就直接跳转到了我们的app中了!

注:用于跳转打开app的域名需要支持https,如果是一级域名页面有个按钮,点击按钮跳转二级域名来打开app,那么二级域名需要支持https。这里DEMO的二级域名不支持https,所以采用的方案是二级域名跳转到一级域名来打开APP。

5.从微信跳转到app的时候,屏幕右上角还有个 “xxx.xx” 的小箭头:点击该箭头,会在Safari中打开该页面。此时再回到微信浏览器中点击 “打开App”按钮,神奇的事情出现了:无法跳转到app!!!

解决方案:在Safari中打开该页面,将网页拉倒最顶部,会出现一个悬浮框,点击悬浮框中的打开按钮,又跳回到app中打开指定页面,此时再回到微信浏览器中点击 “打开App”按钮,又能正常跳转到app了。
Universal Links 功能的接入其实相当于给某些 URL 添加了一种新的打开方式,但是旧的通过浏览器打开 URL 的方式仍然可用,当点击右上角跳转箭头时,相当于又设置这些特定 URL 的默认打开方式为浏览器而非 web,因此一键跳转功能此时会失效。反之通过点击顶部 “打开” 按钮,相当于又将这些特定 URL 的默认打开方式修改为 app ,一键跳转功能恢复正常。
在Safari中打开页面刚进入时,横条是隐藏的,一定要将页面拉到最顶部时才能显示。

6.引导用户去浏览器打开。微信已经屏蔽了通用链接,所以大多数App都做了引导用户去浏览器打开。下一篇文章介绍微信屏蔽通用链接

a5c7p-1lsye.gif