概述
在混合开发中,App 内嵌 H5 是复用 Web 资源、实现动态更新的常见手段(如:活动页面、广告、内部页面)。 这篇文章会拆解双向通信的核心流程,并给出经过验证的代码模板。
通信架构总览
UniApp 的 web-view 在不同平台底层实现差异很大:App 端是原生 webview 渲染,微信小程序端是沙箱隔离的 iframe,H5 端则直接转成了 iframe。
但通信 API 的设计是统一的:
- H5 → App :H5 调用
uni.postMessage,App 在<web-view>的@message事件中接收。 - App → H5 :App 通过
webviewContext.evalJS()执行 H5 侧的 JS 函数,实现数据注入或方法调用。
前置准备:引入 JSBridge
无论 H5 项目是用什么框架写的,通信前都必须引入 uni.webview.js。这个文件提供了 uni.postMessage 和平台环境探测能力。
html
xml
<script type="text/javascript" src="https://js.cdn.aliyun.dcloud.net.cn/dev/uni-app/uni.webview.1.5.2.js"></script>
关键注意点 :如果你的 H5 也是 UniApp 编译出来的,全局变量 uni 会被这个引入的 SDK 覆盖。建议把 SDK 的全局变量重命名,比如挂载到 webUni 上,避免冲突。
引入后,监听 UniAppJSBridgeReady 事件再执行业务逻辑:
javascript
javascript
document.addEventListener('UniAppJSBridgeReady', function() {
// 此时 uni 对象可用
console.log('Bridge 就绪');
});
核心通信流程
场景一:H5 向 App 发送消息
H5 侧调用 uni.postMessage,数据必须包裹在 data 对象中:
javascript
php
uni.postMessage({
data: {
action: 'submit',
payload: { orderId: '12345' }
}
});
App 侧在 <web-view> 组件上监听 @message 事件。注意一个细节 :event.detail.data 是一个数组,每次 postMessage 的消息会推入这个数组,取最新一条通常用 [0] 或 [length - 1]:
vue
xml
<template>
<web-view src="https://your-h5.com/page" @message="onMessage"></web-view>
</template>
<script setup>
function onMessage(event) {
const data = event.detail.data[0];
console.log('收到 H5 消息:', data);
}
</script>
场景二:App 主动调用 H5 方法
App 侧需要先获取 webviewContext。这里有一个版本差异需要留意 :鸿蒙平台(HarmonyOS)下 evalJS 无返回值,且 webviewContext 的创建时机和普通 Android/iOS 不同。
推荐在 onReady 生命周期中创建 context:
vue
xml
<script setup>
import { onReady } from '@dcloudio/uni-app';
import { getCurrentInstance } from 'vue';
let webviewContext = null;
onReady(() => {
// 条件编译:鸿蒙平台单独处理
// #ifdef APP-HARMONY
webviewContext = uni.createWebviewContext('myWebview', getCurrentInstance().proxy);
// #endif
// #ifndef APP-HARMONY
webviewContext = uni.createWebviewContext('myWebview');
// #endif
});
function callH5Method() {
webviewContext.evalJS(`
window.receiveFromApp(${JSON.stringify({ type: 'update', id: 1 })})
`);
}
</script>
H5 侧预先定义好被调用的函数:
javascript
javascript
window.receiveFromApp = function(params) {
console.log('收到 App 调用:', params);
// 执行业务逻辑
return { status: 'ok' };
};
跨平台兼容建议
| 平台 | 关键差异 | 推荐做法 |
|---|---|---|
| App | 支持 evalJS 同步/异步返回,能力最全 |
双向通信首选方案 |
| 微信小程序 | postMessage 非实时,需引入微信 SDK |
配合 navigateTo 跳转传参 |
| 支付宝小程序 | 需引入 web-view.min.js,双向通较顺畅 |
可复用 uni.webview 统一封装 |
| H5 端 | web-view 被转为 iframe |
直接用 window.postMessage |
如果项目需要同时兼容多端,建议在 H5 侧封装一个统一的消息发送层,内部通过 uni.getEnv 判断当前环境后走对应通道。