公告:极客时间特别赞助199元礼包:技术专栏专享优惠,以及硅谷&BAT等100+公司的架构演进技术大会实录观看权限>>>

常用唤醒APP的方式

3414次浏览

前言

开工大吉,祝大家2019诸事顺利! 当我们用微信或者浏览器打开一个html5页面的时候,有时候会有浮层,提示要不要打开相关APP,当然也有的会自动唤醒到app中。这种唤醒是如何做到的呢?

今天简单的写下浏览器是如何唤醒APP的。当然,关于唤醒,涉及的东西蛮多,例如地址加参数唤醒,设置唤醒白名单,唤醒黑名单等等。h5地址和Scheme地址的转换等等。本文简单写下唤醒的相关原理。

如下图:

enter image description here

点击浮层,出现如下提示:

enter image description here

请问这是如何做到的呢?

常见唤醒App方式

一、 Scheme 方式

APP需要注册自己的URL Scheme,用来唯一标识一个App。

Scheme格式:://?=

1、iframe方式

var _iframe = document.createElement('iframe');
_iframe.src = scheme;
_iframe.style.display = 'none';
 document.body.appendChild(_iframe);

2、a链接方式

<a href="<scheme域名>://<path>?<params>=<value>">打开APP</a>

3、location.href 直接跳转

window.location.href = "<scheme域名>://<path>?<params>=<value>"

问题:

由于我们没有办法判断用户手机里面安装了APP没有,因此,需要做一个延迟跳转功能。所以当用户没有安装时,通过延迟会跳转到AppStore。iOS9+当跳转App时,会弹出一个弹框,让用户选择是否跳转,此时还在当前页,setTimeout中的代码会继续执行,导致用户还没来得及选择,就已经跳到AppStore。 若用户未安装App,Android上scheme打开失败,没有任何提示,延迟之后,跳下载页。但是iOS9+会先弹出个万恶的跳转失败的弹窗,延迟之后,再跳下载页。

支持情况

URL Scheme方式一直被广泛使用,但是有些App并不认可,比如:微信、手机百度;站在这些App的角度上考虑,他们并不希望用户为了看更多分享内容,跳出自己的App,因此他们就在客户端内拦截了scheme方式呼端,导致URL Scheme方式在微信、手机百度中彻底失效!!!当然微信是存在一个白名单的,对于白名单中的分享链接是不会屏蔽scheme调用的。 安卓App厂商差异很大,情况比较多样化(比如:Android Chrome版本25+通过iframe方式呼端失败 )

兼容性

Android系统:Chrome for Android无法通过iframe方式来调用scheme,而通过a链接的方式可以成功调用,而针对Chrome内核的浏览器如360浏览器,对于iframe和a链接的方式都能支持,所以对Chrome内核的浏览器采用a链接的方式来调用scheme;对于其他浏览器,如UC,QQ浏览器则采用iframe方式调用scheme。 iOS系统:Safari浏览器不支持 iframe可直接做页面跳转;对于UC、Chrome、QQ只能通过a链接方式调用scheme。 上述提到的屏蔽scheme方式的App:呼端失败跳下载页。

二、 Android Intent 方式

在安卓手机的chrome浏览器或者安卓手机浏览器上面,可以intent方式唤醒

intent:
HOST/URI-path
#Intent; 
  package=[string];                 //  android app包名
  action=[string];      
  category=[string];    
  component=[string];               
  scheme=xxxx;                  // 协议头
  S.browser_fallback_url=[url]          // 可选,scheme启动客户端失败时的跳转页,一般为下载页,需编码
end; 

<!--Intent方式呼端-->
<a href="intent://<role>/<path>#Intent;scheme=<scheme>;package=com.domain;S.browser_fallback_url=[url];end">打开APP</a>

三、Universal Links方式唤醒

首先要开启Universal Links开关

步骤如下:

1、注册一个域名并支持https

2、有权限上传到网站根目录.well-known(这个权限是为了上传一个Apple指定的文件apple-app-site-association)

3、创建一个JSON文件名字为apple-app-site-association的文件(文件名必须是这个!!!)

// apple-app-site-association文件配置
{
    "applinks": {
        "apps": [],
        "details": {
            "ZVC23L5QY4.com.domain.app": {
                "paths": ["*"]
             }
        }
     }
  }

微博的配置地址:https://m.weibo.cn/.well-known/apple-app-site-association

携程的配置地址:https://m.ctrip.com/.well-known/apple-app-site-association

当然,淘宝,京东等等都有。

完整唤醒方案

由于我们无法判断用户是否安装App,所以以上所有的方案都只能尝试呼端。整合上述这些方案,具体思路如下:

// iOS9+在开启Universal Link开关的前提下,优先使用Universal Links方式呼端
if (!closeUnilink && isios && iosVer && iosVer >= 9) {
      // 通过Universal Links方式获取通用呼端链接
      const unilink = getUnilink(opts.scheme, opts.unilink);
      if (unilink) {
        window.location.href = unilink;
      }
    } else {
  // 不支持Intent方式,采用 URL Scheme 方式
   if (!canIntent) {
       // iOS9+ Safari 不支持iframe方式
       if (!isWv && (ua.indexOf('safari') > -1 && iosVer && iosVer >= 9)) {
          link(scheme);
        } else {
          iframe(scheme);
        }
        // 处理未安装客户端情况:延迟跳转到下载页
        setTimeout(function () {
              gotoDownload();
            },延长时间);

    } else {
       // Android支持Intent方式时: intent呼起客户端
      intent(scheme);
  }
}

tips:

前面提到的URL Scheme 方式的iframe和a链接方式,需要考虑用户未安装客户端情况:延迟跳转到下载页。这个延长时间的设置很关键!!!延长时间的设定需要考虑:如果延长时间小于App的启动时间,App还未启动,就执行setTimeout代码;如果延长时间较长,当用户未安装App时,需要等待特别久的时间才能执行setTimeout代码。

对代码封装,根据不同业务呼端需求,可以提炼几个可配参数:呼端scheme地址、呼端失败是否跳下载页、下载页链接、呼起客户端失败超时时间、呼起回调;这样做的好处是:调用组件时,根据不同需求传递参数即可。

优化方案

实际测试时发现:当成功呼起App时,用户再次返回到Safari浏览器的页面时已经跳转到下载页面了,此时需要对setTimeout做清除定时器处理。 当本地App被唤起时,App处于设备可视窗口的最高层,此时浏览器进入后台程序页面会被隐藏掉,会触发pagehide与visibilitychange事件,(关于这两个API,不了解的同学可以查看我之前文章:https://www.haorooms.com/post/page_api_cst )。 此时应先清除setTimeout事件;同时,document.hide属性设置为true,所以setTimeout内不做跳转处理,防止页面跳转到下载页面。

实际开发中,为了防止某些浏览器不支持这个 Page Visibility API,最好同时监听pagehide事件,这样会比较保险(相关代码如下)。

// 页面隐藏时触发
window.onpagehide = function () {
   if (timeout) {
    clearTimeout(timeout);
   }
 };
// 页面的可见状态变化时,会触发
 visibilitychange = function () {
    const tag = document.hidden || document.webkitHidden;
    if (tag && timeout) {
      clearTimeout(timeout);
    }
  }
document.addEventListener('visibilitychange', visibilitychange, false);
// 兼容多的浏览器事件
document.addEventListener('webkitvisibilitychange', visibilitychange, false);

关于唤醒更多文章,我后期会补充一些。简单的唤醒方式就先写到这里。

Tags: app唤醒唤醒apphtml唤醒

相关文章: