复杂场景下的h5与小程序通信
一、背景
在套壳小程序盛行的当下, h5调用小程序能力来打破业务边界已成为家常便饭,h5与小程序的结合,极大地拓展了h5的能力边界,丰富了h5的功能。使许多以往纯h5只能想想或者实现难度极大的功能变得轻松简单。
但在套壳小程序中,h5与小程序通信存在以下几个问题:
- 注入小程序全局变量的时机不确定,可能调用的时候不存在小程序变量。和全局变量my相关的判断满天飞,每个使用的地方都需要判断是否已注入变量,否则就要创建监听。
- 小程序处理后的返回结果可能有多种,h5需要在具体使用时监听多个结果进行处理。
- 一旦监听建立,就无法取消,在组件销毁时如果没有判断组件状态容易导致内存泄漏。
二、在业务内的实践
-
因业务的特殊性,需要投放多端,小程序sdk的加载没有放到head里面,而是在应用启动时动态判断是小程序环境时自动注入的方式:
export function injectMiniAppScript() {
if (isAlipayMiniApp() || isAlipayMiniAppWebIDE()) {
const s = document.createElement('script');
s.src = 'https://appx/web-view.min.js';
s.onload = () => {
// 加载完成时触发自定义事件
const customEvent = new CustomEvent('myLoad', { detail:'' });
document.dispatchEvent(customEvent);
};
s.onerror = (e) => {
// 加载失败时上传日志
uploadLog({
tip: `INJECT_MINIAPP_SCRIPT_ERROR`,
});
};
document.body.insertBefore(s, document.body.firstChild);
}
}
加载脚本完成后,我们就可以调用my.postMessage
和my.onMessage
进行通信(统一约定h5发送消息给小程序时,必须带action
,小程序根据action
处理业务逻辑,同时小程序处理完成的结果必须带type
,h5在不同的业务场景下通过my.onMessage
处理不同type的响应),比如典型的,h5调用小程序签到:
h5部分代码如下:
// 处理扫脸签到逻辑
const faceVerify = (): Promise<AlipaySignResult> => {
return new Promise((resolve) => {
const handle = () => {
window.my.onMessage = (result: AlipaySignResult) => {
if (result.type === 'FACE_VERIFY_TIMEOUT' ||
result.type === 'DO_SIGN' ||
result.type === 'FACE_VERIFY' ||
result.type === 'LOCATION' ||
result.type === 'LOCATION_UNBELIEVABLE' ||
result.type === 'NOT_IN_ALIPAY') {
resolve(result);
}
};
window.my.postMessage({ action: SIGN_CONSTANT.FACE_VERIFY, activityId: id, userId: user.userId });
};
if (window.my) {
handle();