欢迎光临
我们一直在努力

HarmonyOS7 WebView 混合开发:原生和 H5 通信的 4 种姿势

文章目录

      • 前言
      • WebView 基础搭建
      • 4 种通信方式对比
      • JS 调原生:javaScriptProxy
      • 原生调 JS:runJavaScript
      • Cookie 与登录态
      • 踩坑:白屏问题
      • 写在最后

前言

做移动开发,纯原生的项目越来越少了。老板要快、要省钱、要热更新,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 存储
}
}
}

A hand-drawn doodle illustration on pure white pap

关键代码讲解:

  • setWebDebuggingAccess(true) —— 开发阶段必开,不然 Chrome DevTools 调不了 H5 页面,上线前关掉
  • javaScriptAccess(true) —— 不开的话 JS 啥都干不了,通信全废
  • domStorageAccess(true) —— H5 用 localStorage 的话必须开
  • $rawfile('index.html') —— 加载本地文件用 $rawfile,加载网络 URL 直接写字符串

注意:加载网络页面需要在 module.json5 里加 ohos.permission.INTERNET 权限。

4 种通信方式对比

A hand-drawn doodle illustration on pure white pap

原生和 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
})
}
}
}

A hand-drawn doodle illustration on pure white pap

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)
未经允许不得转载:171主机测评 » HarmonyOS7 WebView 混合开发:原生和 H5 通信的 4 种姿势
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址