通过URL Scheme方式唤起APP

6,240 阅读2分钟

唤起APP时遇到的坑以及解决思路。

需求描述:webView唤起手机APP,如果有就唤起,如果没有就跳到下载页。

1.如何唤起APP?

URL Scheme

通过URL Scheme方式唤起APP的主流方法有两种iframe唤起和location.href

  • iframe
let ifr = document.createElement('iframe');
let scheme = 'weixin://';
ifr.src = scheme;
ifr.style.display = 'none';
document.body.appendChild(ifr);

兼容性较差, 在 ios 9+ 上诸如 safari、UC、QQ浏览器中,以及安卓 chrome 25+ 版本,均无法唤起 APP。

  • location.href
window.location.href = 'weixin://';

兼容性相比iframe好很多

2.如何得知APP是否成功唤起?

浏览器实际上没有能力判断手机里是否安装了某个App,也无法判断APP是否被唤起。 但是APP被成功唤起时,H5被切换至后台,换言之只要我们能够监听到页面被切换至后台这个动作,就可以认为APP被成功唤起。

visibilitychange

visibilitychangeH5新增API,可以监听页面被切换操作,当浏览器的某个标签页切换到后台,或从后台切换到前台时就会触发该事件。

window.addEventListener('visibilitychange', () => {
    if(document.visibilityState === 'hidden'){
        alert('页面已被切换至后台');
    };
})

visibilityState作用是记录当前标签页在浏览器中的激活状态。当document.visibilityState的值为hidden时,即页面被切换至后台。

但是在IOS中为了节省资源,浏览器切换到后台或者锁屏时JS会被挂起visibilitychange事件无效。

setTimeout

如果app被唤醒浏览器进入后台JS被挂起,JS虽然不执行,但计时器会被推迟,那么用户从进入APP到切换回浏览器通常会超过1s,如果我们检测到计时器的执行被推迟超过1s,即可认为APP成功唤起导致浏览器进入后台;

let start = new Date().getTime();
setTimeout(()=>{
    if((new Date().getTime()) - start > 3000){
        alert('success');
    }else {
        alert('failed');
    };
},2000);

完整代码如下:

export function callApp(schema,timeOut) {
    let timer,start = new Date().getTime();
    let myPromise = new Promise((resolve, reject)=>{
        window.location.href = schema;
        window.addEventListener('visibilitychange', () => {
            if(document.visibilityState === 'hidden'){
                clearTimeout(timer);
                resolve();
            };
        });
        timer = setTimeout(()=>{
            let end = new Date().getTime();
            if(end - start > timeOut + 1000){
                clearTimeout(timer);
                resolve();
            }else {
                reject();
            };
        },timeOut);
    })
    return myPromise
}

......

callApp('weixin://').then(()=>{
    alert('success');
})
.catch(()=>{
    alert('failed');
})

在规定的时间内(timeOut),倘若未检测到visibilitychange事件或计时器延时触发,则断定APP唤起失败(reject