注册
web

微信内H5页面唤醒App

首先,简述一下这个需求的背景,产品希望能够让用户在微信内,打开一个h5页面,然后就能唤醒公司中维护的app,这个是为了能够更好的引流。


唤醒app的三种方案


IOS系统-Universal Link(通用链接)


Universal Links可以通过配置指定域名路径直接唤醒APP,一步到位


具体配置看这篇文章


juejin.cn/post/693761…


遇到的问题:


apple-app-site-association文件放在app域名(假设: my.app.com/)下


{
"applinks": {
"apps": [],
"details": [
{
"appID": "******",
"paths": [ "/abc/*" ]
},
]
}
}

使用Universal Link其实就是跳转到一个页面(中间页),地址:my.app.com/abc/index.h…


根据上面配置,这个地址是已经固定了的,这需要跟app域名保持一致,并且在paths配置里面的目录下,为了能够获取到apple-app-site-association文件


const universalLink = 'https://my.app.com/abc/index.html?redirectUrl=' + window.location.href
location.replace(universalLink);

如果未下载app,则会跳转失败,在中间页中处理,跳转失败后再返回到当前页面。


<script>
function getQueryStringArgs(url, opt) {
const { decode = true, multiple = false } = opt || {};
const args = {};
if (!(typeof url === 'string' && url.includes('?'))) return args;

const arr = url.split('?');
const qs = arr.length === 2 ? arr[1] : '';
if (!(typeof qs === 'string' && qs.length)) return args;

const items = qs.split('&');
for (let i = 0; i < items.length; i++) {
const meta = items[i];
if (!(typeof meta === 'string' && meta.includes('='))) continue;
const item = meta.split('=');
const key = decode ? decodeURIComponent(item[0]) : item[0];
const value = decode ? decodeURIComponent(item[1]) : item[1];
if (Object.prototype.hasOwnProperty.call(args, key) && multiple) {
const temp = args[key];
args[key] = Array.isArray(temp) ? [...temp, value] : [temp, value];
} else {
args[key] = value;
}
}
return args;
}
const { redirectUrl } = getQueryStringArgs(location.href)
if (typeof redirectUrl === 'string' && redirectUrl) {
location.replace(redirectUrl + '?callType=universalLink') // 处理唤醒app失败场景
}
</script>

上面这段逻辑如果直接放在html中,最好先手动转一下ES5语法,然后压缩一下,这样兼容性好,上面这样展示,是为了可读性好。


总结:


ios系统使用Universal Link在微信和浏览器内都能够正常的唤醒App,且兼容性比较好。但是需要注意中间页域名需要跟app域名保持一致;唤醒app的h5链接域名不能跟中间页域名一致。


直接扫二维码进入另一个页面,需要进行点击操作才能跳转,IOS不允许打开页面立刻就跳转。


URL-Schemes


URL scheme是App提供给外部的可以直接操作App的规则。



  • 比如微信提供了打开扫一扫的URL scheme。weixin://dl/scan
  • 比如支付宝提供了转账的URL scheme。alipayqr://platformapi/startapp?saId=20000116
  • 比如知乎提供了打开回答页面的URL scheme。zhihu://answers/{id}

如何找到某个app的URL Scheme呢?可以看下面这篇文章


zhuanlan.zhihu.com/p/53439246


安卓唤醒app呢,就是使用这种方式


比如:安卓开发提供的是


那跳转的链接是什么样的呢?


const schemeURL = 'myapp://www.myapp.apk'
window.href = schemeURL;

如何判断唤醒失败呢?


没有什么好办法来判断,后面只能触发了唤醒操作之后,监听页面几秒之后是否隐藏来判断,目前默认是2秒


export function getSupportedProperty() {
let hidden;
let visibilityChange;

if (typeof document.hidden !== 'undefined') {
// Opera 12.10 and Firefox 18 and later support
hidden = 'hidden';
visibilityChange = 'visibilitychange';
// @ts-ignore
} else if (typeof document.msHidden !== 'undefined') {
hidden = 'msHidden';
visibilityChange = 'msvisibilitychange';
// @ts-ignore
} else if (typeof document.webkitHidden !== 'undefined') {
hidden = 'webkitHidden';
visibilityChange = 'webkitvisibilitychange';
}

return {
hidden,
visibilityChange,
};
}
/**
* 判断页面是否隐藏(进入后台)
*/

export function isPageHidden() {
const ob = getSupportedProperty();
const hidden = ob?.hidden;
if (typeof hidden === 'undefined') return false;
// @ts-ignore
return document[hidden];
}
/**
* 检测是否唤端成功
* 在唤起执行后,当前页面调用此方法根据页面隐藏变化检测是否唤醒成功
* @param {number} timeout 定时时间,默认2秒
* @return {Object} Promise对象
*/

export function checkOpen(timeout = 2000) {
return new Promise((resolve, reject) => {
const ob = getSupportedProperty();
const visibilityChange = ob?.visibilityChange;

const check = () => {
const pageHidden = isPageHidden();
if (pageHidden) {
resolve(); // 页面被隐藏,说明唤醒成功
} else {
reject(new Error('唤醒超时'));
}
};
const timer = setTimeout(() => {
check();
}, timeout);

const fn = () => {
if (typeof visibilityChange !== 'undefined') {
document.removeEventListener(visibilityChange, fn);
} else {
window.removeEventListener('pagehide', fn);
}
check(); // 唤醒执行后,立马触发页面隐藏变化,可检测是否唤醒成功
clearTimeout(timer); // 未到达指定时间,页面隐藏变化,清除定时器
};

if (typeof visibilityChange !== 'undefined') {
document.addEventListener(visibilityChange, fn);
} else {
window.addEventListener('pagehide', fn);
}
});
}

总结:


安卓使用URL Schemes在微信中是不能跳转的,在浏览器中是能够正常拉起。


微信开放标签


由于在微信环境内,所以可以使用微信提供的能力来唤醒app,微信内禁止使用URL Schemes唤醒app,其实就是微信的一种保护机制。


微信文档:


developers.weixin.qq.com/doc/oplatfo…



如上图,使用这个功能,有很多限制,而且需要配置,但是为了安卓用户成功引流,产品还是要求使用这个功能。


微信配置


1.关联App-微信开发平台


微信开发平台配置关联App,关联App需要appId,已经有App的域名


微信开发平台地址: open.weixin.qq.com/



2.H5页面域名配置-微信公众平台


JS安全域名需要配置当前h5页面的域名


微信公众号地址: mp.weixin.qq.com/



3.初始化微信SDK,需要获取签名


微信开发SDK文档


developers.weixin.qq.com/doc/offiacc…


这需要后端开发接口, 去获取签名



使用微信开放标签说明:


developers.weixin.qq.com/doc/offiacc…


async getWxSignatureData() {
const url = window.location.href.split('#')[0];
const res = await getJsapiSignParamers(url);
const { appId, signature, timestamp, nonceStr } = res.data;
wx.config({
debug: false,
appId: appId,
timestamp: timestamp,
nonceStr: nonceStr,
signature: signature,
jsApiList: ['showOptionMenu'], // 必填,故使用一个非实际使用的api用于填充
openTagList: ['wx-open-launch-app'], // 可选,需要使用的开放标签列表
});

wx.ready(() => {
console.info('wx sdk ready');
console.info('调用接口初始化wx sdk 成功');
this.initWxSDKStatus = 'success';
});

wx.error(res => {
console.error('调用接口初始化wx sdk 失败', res);
this.initWxSDKStatus = 'fail';
});
},

接口返回的就是这样的数据结构



只有这样才能正常初始化微信的SDK,只有正常初始化SDK才能够使用微信开放标签的能力。


然后后端开发的时候要注意:签名需要后端配置白名单ip,文档说明如下:


developers.weixin.qq.com/doc/offiacc…



安卓手机,如果出现唤醒app之后,打开了应用,但是并未成功唤起,那是因为Android应用有要求,需要安卓开发兼容一下就行了~



微信环境内场景


接下来就分析一下,在微信中有几种分享的场景:


1.微信好友之间链接分享



这种方式,使用微信标签是不能唤醒App的,除非是在关注公众号里面,这个公众号就是上面绑定了JS安全域名的公众号



这样点击这个链接就能正常用微信标签唤醒


2.微信好友之间卡片分享



这种点击打开是能够正常唤醒App的,而且不需要使用公众号,但是这种分享有限制,需要打开页面点击右上角分享给其他好友会带上卡片形式,如果在浏览器中就只是复制链接了,微信不会自动识别成卡片


而且这个分享其实就是微信的一个功能


developers.weixin.qq.com/minigame/de…


3.长按识别二维码识别H5链接



这种也能正常唤醒App,而且不需要关注公众号,也很方便,不需要将链接分享给其他人,只需要将唤醒App的链接做出二维码就行了。


全部流程图


无标题-2023-11-05-1641.png


作者:0522Skylar
来源:juejin.cn/post/7297526380333400083

0 个评论

要回复文章请先登录注册