首页 > 其他分享 >浏览器唤醒 app 解决方案汇总

浏览器唤醒 app 解决方案汇总

时间:2022-10-23 21:10:44浏览次数:80  
标签:function 浏览器 app window && var document 唤醒 APP

原理及说明:

首先:无论 IOS 还是 Android,浏览器无法预知本地是否安装了某个 APP。
功能实现的本质是浏览器通过 URL_scheme 打开 APP。Twitter 就注册自己能被「twitter://」打开。
补充:如果是 APP 之间的互相跳转是很简单的:IOS 可以使用 UIApplication 的 canOpenUrl 方法来监测 URL_scheme 是否能打开对应的 APP。exp:如果「twitter://」检测能被打开,也就说明本地安装了 Twitter 。再用 UIApplication 的 openURL 方法,就能打开 Twitter 了。Android 中的做法类似。

实现方案:以 IOS9 为一个分水岭:

iOS7/iOS8:

iOS 中默认通过 Safari 打开 URL scheme,方法一般如下两种:

1,直跳方式:点击链接、修改 window.location 等。

<a href="schemeUrl"> 唤醒你的 APP</a>
或者:
window.location.href = schemeUrl;

PS:如果 APP 唤醒失败或者未安装的情况,有可能会调到 404 页面。很影响用户体验。一般情况会让他跳到其他页面或者下载 APP

2,iframe 方式:在 body 上添加 iframe,设置src属性为跳转的URL scheme。

这种方法不会引起页面可见的变化(页面变成一个新页面),不会导致浏览器的历史记录的变化。
实现思路:

<a href="APP下载地址">下载或打开APP</a>
<script>
$('a').click(function() {
var ifr = document.createElement('iframe');
ifr.src = '自定义 URL scheme';
ifr.style.display = 'none';
document.body.appendChild(ifr);
setTimeout(function(){
document.body.removeChild(ifr);
}, 3000);
});
</script>

实现思路:点击 a 标签,首先会尝试打开 URL scheme,如果成功,就唤起 APP;如果失败,则跳转到 href 属性,即下载页。
(该方案在很多安卓机型有问题)
Android

$('a').click(function() {
location.href = '自定义 URL scheme';
t = Date.now();
setTimeout(function(){
if (Date.now() - t < 1200) {
location.href = 'Android 下载地址';
}
}, 1000);
return false;
}

理想过程是这样:浏览器尝试打开 URL scheme,在 1 秒计时后,检查当前时间,如果实际时间已过 1200 毫秒,说明唤起 APP 成功(唤起 APP 会让浏览器的定时器变慢);如果没超过 1200 毫秒,很可能是没有安装应用,就跳到下载地址。
或者:

var ifr = document.createElement('iframe');
ifr.src = 'com.baidu.tieba://';
ifr.style.display = 'none';
document.body.appendChild(ifr);
var openTime = +new Date();
window.setTimeout(function(){
document.body.removeChild(ifr);
if( (+new Date()) - openTime > 2500 ){
window.location = 'http://exam.com/xxxx.apk';
}
},2000)

这种方案不稳定:因为 Android 是基于 Linux 的分时多任务的,setTimeout 的基准偏差可能会没那么大。

但如果设置比较小的运行间隔(<30ms),在浏览器或者 webview 中,应用切换到后台,setInterval 会被很明显的延迟执行,比如设置一个运行间隔 20ms,总计运行 100 次的定时器,如果页面一直处于前台,则 100 次跑完,总耗时与 100x20=2000ms 不会有太大差异,但页面在后台运行时,此时间会明显超过 2000ms。可以利用这一点来实现是否成功打开 APP 检测及回调。

function openApp(openUrl, appUrl, action, callback) {
//检查app是否打开
function checkOpen(cb){
var _clickTime = +(new Date());
function check(elsTime) {
if ( elsTime > 3000 || document.hidden || document.webkitHidden) {
cb(1);
} else {
cb(0);
}
}
//启动间隔20ms运行的定时器,并检测累计消耗时间是否超过3000ms,超过则结束
var _count = 0, intHandle;
intHandle = setInterval(function(){
_count++;
var elsTime = +(new Date()) - _clickTime;
if (_count>=100 || elsTime > 3000 ) {
clearInterval(intHandle);
check(elsTime);
}
}, 20);
}

//在iframe 中打开APP
var ifr = document.createElement('iframe');
ifr.src = openUrl;
ifr.style.display = 'none';
if (callback) {
checkOpen(function(opened){
callback && callback(opened);
});
}

document.body.appendChild(ifr);
setTimeout(function() {
document.body.removeChild(ifr);
}, 2000);
}

可以通过 document.hidden 或 document.[webkit|moz|ms] Hidden 来判断页面是否被置入后台(即应用被唤起),或 visibilitychange 事件,但对于 Android 4.4 版本一下则不支持。

iOS9

在 iOS 9 上,iframe 方案变得不可用。
按不能使用之前 Android 的代码,因为在打开自定义 URL scheme 时,会弹出对话框,询问是否用 xx 应用来打开。往往用户还没来得及点击打开,定时器又触发了,导致跳到 App Store。
可以在尝试打开 URL scheme 后,再加一个页面跳转,这样对话框会被覆盖,再刷新页面,就能无需确认唤起 APP:

$('a').click(function() {
location.href = '自定义 URL scheme';
location.href = '下载页';
location.reload();
}

下载页延时 2 秒跳转到 App Store。

APP 已安装这是没问题的,但如果 APP 未安装,跳 App Store 的请求会失败。
这时可以使用两个定时器:

$('a').click(function() {
location.href = '自定义 URL scheme';
setTimeout(function() {
location.href = '下载页';
}, 250);
setTimeout(function() {
location.reload();
}, 1000);
}

不过在 iOS9 中其实是支持 universal link 的,就是一个 http 域名形式,在微信中都可以唤起 APP。如果未安装的话,可以直接引导用户去 APP store 下载。

PS:没有完美的解决方案。

微信中打开

因为微信将唤起本地 APP 的接口给禁了,所以微信中是不能直接唤起 APP 的,一般做法是提示用户在浏览器中打开,之后的流程还是我们上面讲的内容。

但是,在 iOS9 中,这个限制是可以突破的,也就是说可以直接唤起 APP。方法就是使用我们上文提到的 universal link。

在 Android 和 iOS8 及其以下系统中,我们可以利用腾讯的亲儿子:应用宝。把你的唤起地址配置成你 APP 的应用宝地址,微信中跳转到这个地址后,如果用户已经安装了 APP,则可直接唤起,如果没有安装,则可直接点击下载。
PS:一般需要一个中间页面引导用户在尾部浏览器打开。微信唤醒 APP 默认只能到达首页。

需要判断的使用场景:
1,用户是在手机浏览器打开
2,微信浏览器打开
3,PC 中打开
4,universal link 是否被关闭
。。。

其他实现方案:

魔窗的 mLink。只要你加了魔窗的 sdk,就可以通过类似 “​​https://s.mlinks.cc/AA01​​” 的链接,在任何环境下打开你的 APP,兼容超过 600 台以上安卓机型的第三方主流浏览器。不管是在手机浏览器中,还是在微信中打开,你可以指定唤起 APP 后直达 APP 中的某个页面或内容(某个促销商品等),就算用户没安装 APP,点击下载安装之后,再打开,还是跳转到指定的页面。

魔窗使用教程:

需要准备的材料:

1,微信分享 AppID
2,应用宝微下载链接
3,IOS :Bundle ID、URI Scheme、下载地址、Team ID(如果配置了 Universal Link)
4,Android: 包名、URI Scheme、下载地址

后台生成极光魔链位信息

JS 使用:
1,直接引用 mLink JS 文件。不要下载之后放入项目
<script src="https://static.mlinks.cc/scripts/dist/mlink.min.js"></script>
2,在 HTML 页面中准备一个或多个用于打开 APP 的 a 元素
<a id="btnOpenApp"> 打开 APP</a>

  1. 极光魔链后台配置好 mLink 必要参数并且生成一条短链





    图片.png
  2. 初始化 mLink
new Mlink({
mlink:'https://a.mlinks.cc/ABCD',//短链地址
button:document.querySelector('a#btnOpenApp')
});
/* ------ 或 -------- */
var link='https://a.mlinks.cc/ABCD';//短链地址
var btn_1=document.querySelector('a#btnOpenApp1');
var btn_2=document.querySelector('a#btnOpenApp2');
var btn_3=document.querySelector('a#btnOpenApp3');

var options = [
{
mlink: link+'?name=1',
button: btn_1
}, {
mlink:link+'?name=2',
button: btn_2
}, {
mlink: link+'?name=3',
button: btn_3
}
];

new Mlink(options);
  1. 在 H5 页面中使用默认短链接进行动态传参





    图片.png
  2. options 选项
{
mlink: "短链KEY",
button: document.querySelector('a#btnOpenApp'),
autoLaunchApp : false,
autoRedirectToDownloadUrl: true,
downloadWhenUniversalLinkFailed: false,
inapp : false,
params: {}
}

​具体参数含义见链接:​

补充:

京东兼容性解决方案:

(function(){
// 判断浏览器
var Navigator = navigator.userAgent;
var ifChrome = Navigator.match(/Chrome/i) != null && Navigator.match(/Version\/\d+\.\d+(\.\d+)?\sChrome\//i) == null ? true : false;
var ifAndroid = (Navigator.match(/(Android);?[\s\/]+([\d.]+)?/)) ? true : false;
var ifiPad = (Navigator.match(/(iPad).*OS\s([\d_]+)/)) ? true : false;
var ifiPhone = (!ifiPad && Navigator.match(/(iPhone\sOS)\s([\d_]+)/)) ? true : false;
var ifSafari = (ifiPhone || ifiPad) && Navigator.match(/Safari/);
var version = 0;
ifSafari && (version = Navigator.match(/Version\/([\d\.]+)/));

version = parseFloat(version[1], 10);
// 是否从微信打开
var ifWeixin = navigator.userAgent.indexOf("MicroMessenger") >= 0; // weixin
var j = false;
var iframe = "plugIn_downloadAppPlugIn_loadIframe";
var t = false;
var i = 0;
var B = {};
var b = {};
var selector = null;
var Hquery = {};
// 判断当前使用的js框架是zepto还是jquery
var Query = window.Zepto || window.jQuery ? true : false;
var g = [];
// 是否存在html5的localStorage 存储
var v = window.localStorage ? true : false;
var o = "mdownloadAppPlugInskip";
var p = null;

function m() { // 打印时间 例如:2016-5-18
var M = new Date();
var N = M.getFullYear();
var O = M.getMonth() + 1;
var L = M.getDate();
strDate = N + "-" + O + "-" + L;
return strDate
}
// 微信相关操作
function r() { // weixin api
WeixinJSBridge.invoke("getInstallState", {
packageName: "com.jingdong.app.mall",
packageUrl: "openApp.jdMobile://"
}, function(M) {
var N = M.err_msg,
L = 0;
if (N.indexOf("get_install_state:yes") > -1) {
j = true
}
})
}
// 根据是否存在js框架进行dom和时间的绑定
function bind(dom, event, fun) { // bind event
if (Query) {
selector("#" + dom).bind(event, fun)
} else {
selector("#" + dom).addEventListener(event, fun, !1)
}
}

function z(L) {
var M = (L || "mGen") + (++i);
return M
}
// 微信操作
if (ifWeixin) { // if navigitor is weixin
if (window.WeixinJSBridge && WeixinJSBridge.invoke) {
r()
} else {
document.addEventListener("WeixinJSBridgeReady", r, !1)
}
}

// 如果存在js框架
if (Query) {
selector = window.$;
Hquery = window.$
} else {
selector = function(obj) {
if (typeof obj == "object") {
return obj
}
return document.querySelector(obj);
};
if (!window.$) {
window.$ = Hquery = selector
} else {
Hquery = window.$
}
}
window.onblur = function() {
for (var L = 0; L < g.length; L++) {
clearTimeout(g[L])
}
};
// 设置cookie。
function e(N) {
var M = document.cookie.indexOf(N + "=");
if (M == -1) {
return ""
}
M = M + N.length + 1;
var L = document.cookie.indexOf(";", M);
if (L == -1) {
L = document.cookie.length
}
return document.cookie.substring(M, L)
}
// 设置cookie
function l(N, P, L, Q, O) {
var R = N + "=" + escape(P);
if (L != "") {
var M = new Date();
M.setTime(M.getTime() + L * 24 * 3600 * 1000);
R += ";expires=" + M.toGMTString()
}
if (Q != "") {
R += ";path=" + Q
}
if (O != "") {
R += ";domain=" + O
}
document.cookie = R
}

// 打开的链接集合
function F(L) {
var url = {
downAppURl: "http://h5.m.jd.com/active/download/download.html?channel=jd-m",
downAppIos: "http://union.m.jd.com/download/go.action?to=http%3A%2F%2Fitunes.apple.com%2Fcn%2Fapp%2Fid414245413&client=apple&unionId=12532&subunionId=m-top&key=e4dd45c0f480d8a08c4621b4fff5de74",
downWeixin: "http://a.app.qq.com/o/simple.jsp?pkgname=com.jingdong.app.mall&g_f=991850",
downIpad: "https://itunes.apple.com/cn/app/jing-dong-hd/id434374726?mt=8",
inteneUrl: "openApp.jdMobile://360buy?type=1",
inteneUrlParams: null,
openAppBtnId: "",
closePanelBtnId: "",
closePanelId: "",
closeCallblack: null,
closeCallblackSource: null,
cookieFlag: null,
noRecord: false,
sourceType: "JSHOP_SOURCE_TYPE",
sourceValue: "JSHOP_SOURCE_VALUE",
openAppEventId: "MDownLoadFloat_OpenNow",
closePanelEventId: "MDownLoadFloat_Close"
};
if (L) {
for (var M in L) {
if (M && L[M]) {
url[M] = L[M]
}
}
}
return url
}
// 敲黑板 重点内容。看京东是怎么解决兼容问题的。
function openApp(N, L) { // openApp
var R = h(N); //获取相对应的url
var O = null;
if (ifWeixin) { // 如果是微信端
var M = null;
if (j) {
M = R
} else {
M = N.downWeixin
}
location.href = M; // 直接使用location.href打开
return
}
if (ifiPad) { // 如果是ipad
O = N.downIpad
} else {
if (ifiPhone) { // 如果是iphone
O = N.downAppIos
} else {
O = N.downAppURl
}
}

if (ifChrome) { // 如果是chrome
if (ifAndroid) { //安卓浏览器
var Q = R;
R = y(Q);
// 延后50毫秒
setTimeout(function() {
window.location.href = R
}, 50)
}
}
if (ifSafari && version >= 9) { // 判断safari版本 如果大于9
setTimeout(function() { // 必须要使用settimeout
var S = document.createElement("a"); //创建a元素
S.setAttribute("href", R), S.style.display = "none", document.body.appendChild(S);
var T = document.createEvent("HTMLEvents"); // 返回新创建的 Event 对象,具有指定的类型。
T.initEvent("click", !1, !1)// 初始化新事件对象的属性, S.dispatchEvent(T) // 绑定事件
}, 0)
} else {
document.querySelector("#" + iframe).src = R // 将iframe增加src
}
var P = Date.now();
setTimeout(function() {
if (L) {
var S = setTimeout(function() {
x(P, O)
}, 1500);
g.push(S)
}
}, 100)
}
// x方法
function x(N, downUrl) {
var L = Date.now();
if (N && (L - N) < (1500 + 200)) {
window.location.href = downUrl
}
}

function h(N) {
var V = [];
var P = N.inteneUrlParams;
var T = {
category: "jump",
des: "productDetail"
};
if (N.sourceType && N.sourceValue) {
T.sourceType = N.sourceType;
T.sourceValue = N.sourceValue;
if (P && !P.sourceType && !P.sourceValue) {
P.sourceType = N.sourceType;
P.sourceValue = N.sourceValue
}
}
if (P) {
for (var U in P) {
if (U && P[U]) {
V.push('"' + U + '":"' + P[U] + '"')
}
}
} else {
for (var U in T) {
if (U && T[U]) {
V.push('"' + U + '":"' + T[U] + '"')
}
}
}
try {
var Q = MPing.EventSeries.getSeries();
if (Q) {
var W = JSON.parse(Q);
W.jdv = encodeURIComponent(e("__jdv"));
W.unpl = encodeURIComponent(e("unpl"));
W.mt_xid = encodeURIComponent(e("mt_xid"));
W.mt_subsite = encodeURIComponent(e("mt_subsite"))
}
var S = {
mt_subsite: encodeURIComponent(e("mt_subsite")),
__jdv: encodeURIComponent(e("__jdv")),
unpl: encodeURIComponent(e("unpl")),
__jda: encodeURIComponent(e("__jda"))
};
Q = JSON.stringify(W);
V.push('"m_param":' + Q);
V.push('"SE":' + JSON.stringify(S))
} catch (R) {
V.push('"m_param":null')
}
var M = "{" + V.join(",") + "}";
var O = N.inteneUrl.split("?");
var L = null;
if (O.length == 2) {
L = O[0] + "?" + O[1] + "¶ms=" + M
} else {
L = O[0] + "?params=" + M
}
return L
}

function y(L) {
return "intent://m.jd.com/#Intent;scheme=" + L + ";package=com.jingdong.app.mall;end"
}

function n(L) {
if (L.openAppBtnId) {
B[L.openAppBtnId] = L;
G(L.openAppBtnId, L.openAppEventId);
bind(L.openAppBtnId, "click", function() {
var P = this.getAttribute("id");
var M = B[P];
if (!t) {
var N = document.createElement("iframe");
N.id = iframe;
document.body.appendChild(N);
document.getElementById(iframe).style.display = "none";
document.getElementById(iframe).style.width = "0px";
document.getElementById(iframe).style.height = "0px";
t = true
}
var O = M.cookieFlag ? "downloadAppPlugIn_downCloseDate_" + M.cookieFlag : "downloadAppPlugIn_downCloseDate";
l(O, Date.now() + "_2592000000", 60, "/", "m.jd.com");
l(O, Date.now() + "_2592000000", 60, "/", "m.jd.hk");
openApp(M, true)
})
}
}

function D(M) {
if (M.closePanelBtnId && M.closePanelId) {
B[M.closePanelBtnId] = M;
G(M.closePanelBtnId, M.closePanelEventId);
var Q = M.cookieFlag ? "downloadAppPlugIn_downCloseDate_" + M.cookieFlag : "downloadAppPlugIn_downCloseDate";
var O = e(Q);
var P = null;
if (O) {
P = O.split("_");
if (P.length == 2) {
P[0] = parseInt(P[0], 10);
P[1] = parseInt(P[1], 10)
} else {
P = null
}
}
var L = Date.now();
if (Html5Plus() || (!M.noRecord && P && P.length == 2 && (L - P[0]) < P[1])) {
document.querySelector("#" + M.closePanelId).style.display = "none";
if (M.closeCallblack) {
var N = M.closeCallblackSource ? M.closeCallblackSource : null;
M.closeCallblack.call(N)
}
return
} else {
document.querySelector("#" + M.closePanelId).style.display = "block"
}
bind(M.closePanelBtnId, "click", function() {
var U = this.getAttribute("id");
var R = B[U];
var T = R.cookieFlag ? "downloadAppPlugIn_downCloseDate_" + R.cookieFlag : "downloadAppPlugIn_downCloseDate";
if (!R.noRecord) {
l(T, Date.now() + "_259200000", 60, "/", "m.jd.com");
l(T, Date.now() + "_259200000", 60, "/", "m.jd.hk")
}
document.querySelector("#" + R.closePanelId).style.display = "none";
if (R.closeCallblack) {
var S = R.closeCallblackSource ? R.closeCallblackSource : null;
R.closeCallblack.call(S)
}
})
}
}

function Html5Plus() { // htmlplus
if (Navigator.indexOf("Html5Plus") >= 0) {
return true
} else {
return false
}
}

function G(P, M) {
try {
var O = document.getElementById(P);
var L = O.className;
if (L) {
L = L + " J_ping"
} else {
L = "J_ping"
}
O.className = L;
O.setAttribute("report-eventid", M)
} catch (N) {}
}

function C(L) {
var M = F(L);
n(M);
D(M)
}
Hquery.downloadAppPlugIn = C;
Hquery.downloadAppPlugInOpenApp = function(L) {
var M = F(L);
openApp(M);
}
});

参考文章:

​京东在 html5 页面中打开本地 app 的解决方案​Ios/Android h5 唤起本地 APP
iOS/Android 浏览器 (h5) 及微信中唤起本地 APP
极光魔链 mLink JS 集成文档
H5 链接打开原生 App 并跳转到指定界面



作者:前端小学生_f675

链接:https://www.jianshu.com/p/62adf3cac8f2

来源:简书

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

标签:function,浏览器,app,window,&&,var,document,唤醒,APP
From: https://blog.51cto.com/deng/5787563

相关文章

  • SpringBoot项目整合Mybatis时Mapper.xml文件的存放位置
    SpringBoot项目整合Mybatis时Mapper.xml文件的存放位置目录:方式一:放在与Mapper接口同级目录方式二:在resources创建Mapper接口同名文件夹用来存放Mapper.xml文件方式三:......
  • MacBook M1系统启动MxSrvs中的nginx报错:nginx: [emerg] getgrnam("root") failed in /
    nginx报错:nginx:[emerg]getgrnam("root")failedin/Applications/MxSrvs/bin/nginx/conf/nginx.conf:1nginx:[emerg]getgrnam("wangteng")failedin/Applications......
  • .NET 6学习笔记(4)——如何在.NET 6的Desktop App中使用Windows Runtime API
    WindowsRuntimeAPI是当初某软为了区别Win32API,力挺UWP而创建的另一套Windows10专用的API集合。后来因为一些原因,UWP没火。为了不埋没很有价值的WindowsRuntimeAPI,某......
  • app自动化测试环境安装
    一、环境依赖app自动化测试环境如下:appium服务第三方库appium-python-client手机或模拟器java环境jdk1.8android环境二、appium服务安装1、下载地址http://appi......
  • 有哪些APP安全小测试
    app安全测试方法小百科​随着无线网络和移动通信技术的发展,智能手机功能日趋强大,因此也将APP市场带动了起来。但是随着手机操作系统日益标准化,网络出击手段不同往日,黑客已经......
  • app安全测试方法小百科
     随着无线网络和移动通信技术的发展,智能手机功能日趋强大,因此也将APP市场带动了起来。但是随着手机操作系统日益标准化,网络攻击手段不同往日,黑客已经可以像攻击电脑信息......
  • 如何测试一个APP的登录场景?-小白妹
    如何测试一个APP的登录场景页面基本元素的操作;大量字符,特殊字符,边界值,必填项校验;注册手机号的特殊性验证,注册邮箱的格式验证;密码大小写是否敏感,密码是否加密展示,密码是否有......
  • uniapp返回页面不刷新页面视图(nvue)
    安卓别的程序没有试问题1我在app.vue页面里onLaunch生命周期写了‘uni.getStorageSync()’,导致我在其它页面返回上一页的时候‘onShow’出现了‘uni.getStorageSync()......
  • #打卡不停更#【FFH】Openharmony学生挑战赛分享-少儿语言教育APP
    Openharmony学生挑战赛经验分享前言本次参赛的项目是基于openHarmony开发的北向应用-少儿语言文化教育APP。从项目成立到初版成型再到参加比赛,这一路上遇到了不少困难,我也......
  • Add AutoMapper
    (注:本文示例使用的是.NETCore3.1)1.配置(Configuration)Reference:https://docs.automapper.org/en/latest/Configuration.html多种方法配置,这里推荐使用配置文件......