HarmonyOS7 WebView 混合开发:原生和 H5 通信的 4 种姿势
前言
做移动开发,纯原生的项目越来越少了。老板要快、要省钱、要热更新,H5 混合开发基本是标配。但混合开发最头疼的事就是——原生和 H5 怎么通信?H5 要调原生的支付,原生要往 H5 里塞数据,登录态怎么同步?
HarmonyOS7 的 WebView 组件提供了好几种通信方式,我整理了 4 种最常用的姿势,帮你一次搞明白。
WebView 基础搭建
先看怎么创建一个最基础的 WebView:
import { webview } from '@kit.ArkWeb';
@Entry
@Component
struct WebViewBasic {
controller: webview.WebviewController = new webview.WebviewController();
aboutToAppear() {
webview.WebviewController.setWebDebuggingAccess(true); // 开启调试
}
build() {
Column() {
Web({
src: $rawfile('index.html'), // 加载本地 H5
controller: this.controller
})
.width('100%')
.height('100%')
.javaScriptAccess(true) // 允许执行 JS
.domStorageAccess(true) // 允许 DOM 存储
}
}
}

关键代码讲解:
setWebDebuggingAccess(true)—— 开发阶段必开,不然 Chrome DevTools 调不了 H5 页面,上线前关掉javaScriptAccess(true)—— 不开的话 JS 啥都干不了,通信全废domStorageAccess(true)—— H5 用 localStorage 的话必须开$rawfile('index.html')—— 加载本地文件用$rawfile,加载网络 URL 直接写字符串
注意:加载网络页面需要在
module.json5里加ohos.permission.INTERNET权限。
4 种通信方式对比

原生和 H5 通信,核心就两个方向:H5 调原生 和 原生调 H5。
| 方式 | 方向 | 核心 API | 适用场景 |
|---|---|---|---|
| javaScriptProxy | H5 → 原生 | Web.javaScriptProxy() |
H5 调支付、弹窗、设备能力 |
| registerJavaScriptProxy | H5 → 原生 | controller.registerJavaScriptProxy() |
动态注册,更灵活 |
| runJavaScript | 原生 → H5 | controller.runJavaScript() |
原生主动调 H5 函数 |
| 消息通道 | 双向 | onMessage / postMessage |
长连接、频繁通信 |
实际开发中,javaScriptProxy + runJavaScript 这俩组合就能覆盖 90% 的场景。下面重点讲。
JS 调原生:javaScriptProxy
这是最常用的方式——把原生对象注入到 H5 的 window 上,H5 像调本地方法一样调原生。
// 1. 定义原生桥接类
class NativeBridge {
private controller: webview.WebviewController | null = null;
setController(ctrl: webview.WebviewController) {
this.controller = ctrl;
}
showToast(msg: string) {
promptAction.showToast({ message: msg });
}
getUserInfo(): string {
return JSON.stringify({ name: '张三', id: '10086' });
}
requestPayment(amount: string): void {
// 调起原生支付
console.info(`发起支付:${amount}元`);
// 支付完成后通过 runJavaScript 通知 H5 结果
this.controller?.runJavaScript(`onPaymentResult(true)`);
}
}
// 2. 注入到 WebView
@Entry
@Component
struct WebViewDemo {
controller: webview.WebviewController = new webview.WebviewController();
@State bridge: NativeBridge = new NativeBridge();
aboutToAppear() {
this.bridge.setController(this.controller);
}
build() {
Column() {
Web({ src: $rawfile('index.html'), controller: this.controller })
.javaScriptProxy({
object: this.bridge, // 注入的原生对象
name: "nativeBridge", // H5 通过 window.nativeBridge 调用
methodList: ["showToast", "getUserInfo", "requestPayment"], // 暴露的方法
controller: this.controller
})
}
}
}

H5 侧这样调用:
// H5 页面中的代码
function callNative() {
// 调用原生 Toast
window.nativeBridge.showToast('来自H5的问候');
// 获取用户信息
const user = JSON.parse(window.nativeBridge.getUserInfo());
console.log(user.name); // 张三
// 发起支付
window.nativeBridge.requestPayment('9.9');
}
关键代码讲解:
object: this.bridge—— 要注入的原生对象实例name: "nativeBridge"—— H5 通过window.nativeBridge访问,名字自定义methodList—— 只有列在里面的方法才能被 H5 调用,安全控制靠这个requestPayment里调runJavaScript('onPaymentResult(true)')—— 原生处理完再通知 H5,形成请求-响应闭环
这个闭环模式很重要:H5 调原生 → 原生处理 → 原生通过 runJavaScript 回调 H5。混合开发大多数交互都这么搞。
原生调 JS:runJavaScript
原生主动调 H5 的场景也很多——登录完成后通知 H5 刷新、推送消息到了让 H5 更新 UI。
Button('通知H5登录成功')
.onClick(() => {
const token = 'abc123xyz';
this.controller.runJavaScript(`onLoginSuccess('${token}')`);
})
Button('更新H5数据')
.onClick(() => {
const data = JSON.stringify({ count: 42, status: 'ok' });
this.controller.runJavaScript(`updateData(${data})`);
})
关键代码讲解:
runJavaScript参数是一段 JS 代码字符串,不是函数名- 传参要自己拼字符串,注意引号转义和 JSON 序列化
- 调用时机要确保 H5 页面已经加载完成,在
onPageEnd回调后再调比较稳
还有个升级版 runJavaScriptExt,支持返回 ArrayBuffer 二进制数据,适合需要传图片、文件的场景。
Cookie 与登录态
混合开发绕不开的问题:原生登录了,H5 怎么同步登录态? 答案是 Cookie。
import { webview } from '@kit.ArkWeb';
// 设置 Cookie
webview.WebCookieManager.setCookie('https://example.com', 'token=abc123; Path=/; Max-Age=86400');
// 读取 Cookie
let cookie = webview.WebCookieManager.fetchCookieSync('https://example.com');
console.info(`当前Cookie: ${cookie}`);
// 清除所有 Cookie(退出登录时)
webview.WebCookieManager.deleteEntireCookie();
关键代码讲解:
setCookie—— 设置指定域名的 Cookie,URL 要写完整Max-Age=86400—— 必须加过期时间,否则是 Session Cookie,WebView 关了就没了fetchCookieSync—— 同步获取 Cookie,调试时好用deleteEntireCookie—— 退出登录时清掉,别只清原生的忘了 H5 的
踩坑:
setCookie最好在 WebView 初始化完成后调。太早设可能会被 H5 页面加载时的请求覆盖掉。
踩坑:白屏问题
WebView 白屏,十个混合开发八个遇到过。常见原因和解决:
| 原因 | 现象 | 解决 |
|---|---|---|
| 没加网络权限 | 网络页面完全白 | module.json5 加 INTERNET 权限 |
| JS 执行被禁 | 页面加载了但交互不生效 | javaScriptAccess(true) |
| DOM Storage 被禁 | SPA 页面白屏 | domStorageAccess(true) |
| 混合内容被拦截 | HTTPS 页面加载 HTTP 资源白屏 | 服务端全走 HTTPS |
| WebView 未渲染 | 控件没高度 | 检查 width/height 是否设了 |
| H5 本身报错 | 控制台有 JS 错误 | 开 DevTools 调试排查 |
排查套路:先看高度有没有 → 开 DevTools 看控制台 → 检查权限配置。 大部分白屏问题都是这三类。
写在最后
原生和 H5 通信,记住这个图就够了:
H5 调原生 → javaScriptProxy(注入原生对象)
原生调 H5 → runJavaScript(执行 JS 代码)
登录态同步 → Cookie(WebCookieManager)
别搞复杂了,这仨组合能覆盖绝大多数混合开发场景。真遇到性能瓶颈再考虑消息通道那种重型方案。
有什么 WebView 踩坑经历,评论区聊聊。
更多推荐
所有评论(0)