uni-app 与 WebView 通信需手动搭建桥梁:必须绑定 bindmessage 才能接收 H5 消息,H5 发送需 {data: any} 结构,uni-app 发送须等 bindload 触发后调用 postMessage,且 H5 需检测 window.uni 是否存在,evalJS 可绕过监听限制但有长度限制。
uni-app 与 webview 的通信不是“配好就能用”,而是必须手动搭桥、分阶段激活、按平台约束收发——不满足任一条件,postmessage 就会静默失败或报 is not a function 错误。
web-view 组件必须绑定 bindmessage 才能收到 H5 消息
uni-app 默认不监听 H5 发来的消息,哪怕 H5 调用了 window.uni.postMessage,uni-app 侧也完全无感。必须在 标签上显式声明事件处理器:
-
bindmessage属性值只能是组件 methods 里的函数名(如handleWebViewMessage),不能是箭头函数、内联写法或字符串路径 - 该绑定仅在组件挂载后生效,
mounted钩子中注册无效;iOS 下若 H5 在DOMContentLoaded前就发消息,大概率丢失 - H5 发送的消息结构必须为 {
data: any },否则小程序端无法解析(Android 和 H5 端对结构宽松些,但统一按此格式最稳)
uni-app 向 H5 发消息前必须等 bindload 触发
this.$refs.webview.postMessage() 报 is not a function 的根本原因:web-view 实例尚未完成内部 bridge 初始化,ref 上的 postMessage 方法还没挂载。这不是延迟问题,而是生命周期硬约束。
- 绝对不要在
onLoad、onReady或mounted里直接调用postMessage - 必须监听
bindload事件,在其回调中触发,例如:onWebLoad() { this.$nextTick(() => { this.$refs.webview.postMessage({ data: 'init' }) }) } - 真机调试时,若 H5 页面含重定向(如登录跳转),
bindload可能只触发一次(首屏加载),后续跳转不触发,需在 H5 侧主动重发就绪信号
H5 页面必须检测 window.uni 是否存在再调用 API
很多 H5 开发者直接写 uni.postMessage(...),结果在浏览器环境报 ReferenceError。因为 uni 对象只在 uni-app 注入的 WebView 环境中存在,普通网页里它根本未定义。
- 安全写法是先判断:
if (window.uni && typeof window.uni.postMessage === 'function') { window.uni.postMessage({ data: 'from-h5' }) } - 不要在 iframe 或弹窗子页面里调用,
uni.postMessage只对顶层 web-view 生效 - iOS 仅接受字符串或简单 JSON,建议 H5 发送前统一
JSON.stringify;Android 支持对象,但跨平台时以 iOS 为准 - 若 H5 加载了 CDN 上的 JS,且调用
postMessage时指定了origin,需设为*或匹配 uni-app 的实际来源,否则被浏览器拦截
别忽略 evalJS 是反向通信的唯一可靠方式
uni-app 向 H5 传数据,除了 postMessage,还有更直接的 evalJS:它能在 H5 全局上下文中执行任意 JS 代码。这个能力常被低估,但它解决了 postMessage 的两个硬伤——不依赖 H5 主动监听、可绕过序列化限制。
- 用法示例:
this.$refs.webview.evalJS('handleAppData && handleAppData(' + JSON.stringify(data) + ')') - 前提是 H5 页面已声明全局函数
window.handleAppData,且函数名不能是动态拼接或闭包内定义 -
evalJS在 iOS 上有 100KB 字符串长度限制,超长脚本需分段或改用postMessage - 它不触发 H5 的
message事件,所以和postMessage的接收逻辑完全隔离——这是优势也是陷阱,容易漏掉响应处理
最易被忽略的一点:所有通信都建立在 H5 页面已完整加载并完成 JS 初始化的基础上。如果 H5 本身依赖异步资源(比如懒加载模块、CDN 组件库),光等 bindload 不够,还需 H5 主动发一个 ready 消息,uni-app 收到后再开始业务通信。否则,你永远在调试“为什么第一条消息收不到”。











