需求:
- 若安装app,拉起app
- 未安装app,跳转App Store
背景
- 普通浏览器兼容,微信有权限限制,只能每次跳转下载页
- 前提我们首先知道js无法判断出当前手机里面App是否安装。(假如H5页面在微信内打开,可通过调用微信内部的JS API判断出App是否安装,但是该api并不对外开放)。浏览器中打开H5页面唤起App时也是无法判断出当前app是否安装。
- 拉起app的原理就是js和原生统一好一个地址(ex: xxxx://self/xxx.xxxxpage),然后浏览器发起请求,如果安装了app则会拦截这个请求并且打开。
实现方案
针对这种背景情况 ,目前业内普遍采取两种做法:
-
是利用延时器原理,打开H5页面会尝试唤起App,假如失败了几秒后会直接跳转到下载页面 (缺点是即使用户安装了App过了时间也会跳转到下载页,从App返回到浏览器时也会变成下载页,体验很不好)但是有方案可以解决
-
不采用延时器,直接跳转到App下载页面。
实现
原生侧配置:scheme和host要和js这边保持统一
js侧如下
/* 写法一: */
window.location.href="app的scheme"
setTimeout(function() {
window.location.href="下载地址"
}, 500);
但是以上代码明显有两处问题:
- 单说拉起app,通过a链接或者window.location.href=”xxx”即可,但是某些手机在未安装app时会识别我们上面定义的跳转协议尝试打开这个网页,此时会报找不到网页。这里用iframe的方式兼容性更好。
- 在未安装app时应跳转下载页,写法一直接一个延时跳转一下就行,但拉起app并不会自动清除定时器,即无论是否安装了app,页面在500ms后都会跳转到下载页。
方案一:是用iframe跳转,设置一个初始时间,打开拉起app地址后有个结束时间,计算两者之差,当差大于一定时间时说明安装了app,当差很小是说明没有打开app,此时需要跳转到下载页。
出于节能的考虑, 部分浏览器在进入后台时(或者失去焦点时), 会将 setTimeout 等定时任务暂停待用户回到浏览器时, 才会重新激活定时任务。说是暂停, 其实应该说是延迟, 1s 的任务延迟到 2s, 2s 的延迟到 5s, 实际情况因浏览器而异。
代码如下
/* 优化版的写法一: */
downloadButton.addEventListener('click', function() {
var startTime = new Date();//记录初始时间
var t = 500;
var ifr = document.createElement('iframe');
ifr.src = 'app的scheme';//打开app
document.body.appendChild(ifr);
ifr.onload = function() {
ifr.style.display='none';
setTimeout(function() {
document.body.removeChild(ifr);
var endTime = new Date();//记录结束时间
if (endTime - startTime <= (t + 30)) {
//两者之差小于30ms时跳转到下载页
window.location.href = "下载地址"
}
}, t);
};
})
/*
写法二:
*/
const appDownload = () => {
function failed() {
window.location.href = '应用商店的地址'
}
function transfer(cb) {
window.location.href = 'app的scheme';
const initialTime = new Date();
let counter = 0;
let waitTime = 0;
const checkOpen = setInterval(() => {
counter++;
waitTime = new Date() - initialTime;
if (waitTime > 3500) {
clearInterval(checkOpen);
cb();
}
if (counter < 1000) {
return;
};
}, 20);
document.addEventListener('visibilitychange', () => {
const isHidden = document.hidden;
if (isHidden) {
clearInterval(checkOpen);
}
});
}
transfer(failed);
}
// 如果判断在微信中提示复制链接到浏览器中打开
if(!this.isWeixin()) {
appDownload();
}