H5与鸿蒙原生双向通信实战(JSBridge 基础)
搞定了 ArkWeb 的页面加载、生命周期管理、权限配置、网络白名单和缓存控制。到这里,你的鸿蒙混合项目已经能正常展示 H5、正常联网、不会内存泄漏、不会缓存错乱。
但——只能展示页面的混合应用,毫无实际业务价值。
真正的混合开发核心,只有一件事:让 H5 和鸿蒙原生互相调用、互相传值。
比如这些常见需求:
-
H5 点击按钮,调用鸿蒙原生弹窗、Toast、原生分享
-
H5 提交表单,调用原生获取设备信息、版本号、唯一标识
-
鸿蒙原生主动向 H5 推送数据、推送登录状态、推送事件通知
-
H5 完成操作后,通知原生关闭页面、跳转原生页面
这些功能全部依赖 ArkWeb 双向通信机制,也就是大家常说的 JSBridge。
很多新手在这里踩巨多坑:调用没反应、参数传不过去、回调不触发、页面销毁后桥接报错、重复注册导致内存溢出、H5 端写法不兼容鸿蒙内核……
本篇我带你从零手写一套 HarmonyOS7 标准双向通信方案:原生注册方法给 H5 调用、H5 调用原生、原生主动调用 H5、异步回调返回结果,全程可直接落地项目。
没有过度封装、没有废话、全部是可上线代码。
前置必读:《Web 组件 H5 加载与生命周期管理》《权限、网络白名单与页面缓存控制》两篇生命周期 + 权限配置,本篇基于前两篇完整工程继续迭代。
一、先搞懂:鸿蒙 ArkWeb 双向通信原理
很多人学不懂 JSBridge,是因为完全搞反了调用逻辑。
我用最通俗的人话讲清楚:
1、原生 → H5:
鸿蒙是主人,H5是客人。主人可以随时主动喊话客人,通过 runJavaScript 执行 H5 全局 JS 方法。
2、H5 → 原生:
客人不能随便喊主人,必须主人提前“开放接口、登记方法”,H5 才能调用原生能力。
这个「登记方法」的动作,就是 registerJavaScriptProxy。
再记一个重中之重的版本区别:
HarmonyOS7 对桥接机制做了优化,和旧版鸿蒙语法略有区别,不能直接照搬网上旧代码!
旧版容易出现:注册失效、方法找不到、白屏、内核崩溃。
二、第一步:封装原生可被 H5 调用的工具类
我们需要写一个桥接工具类,专门暴露方法给前端 H5 调用。
规范非常重要:
-
所有给 H5 调用的方法,必须加 @JavaScriptInterface
-
方法必须 public
-
不支持解构、不支持复杂参数、尽量用字符串传参
-
禁止在桥接方法内写耗时同步操作,极易卡死 Web 内核
下面是项目可直接上线的工具类:
import { JavaScriptInterface } from '@kit.ArkWeb';
import { deviceInfo } from '@kit.BasicServicesKit';
export class JsBridgeModel {
// 回调句柄,用于返回数据给H5
public h5Callback: (result: string) => void | null;
// 1. 获取设备基础信息(供H5调用)
@JavaScriptInterface
getDeviceInfo(): string {
return JSON.stringify({
deviceName: deviceInfo.deviceName,
deviceType: deviceInfo.deviceType,
productModel: deviceInfo.productModel
});
}
// 2. 原生弹窗提示
@JavaScriptInterface
showNativeToast(msg: string): void {
console.info("H5调用原生弹窗:", msg);
// 项目中可替换为自己的Toast/Dialog组件
}
// 3. 带回调的原生方法(重点:H5传参、原生处理、返回结果)
@JavaScriptInterface
getNativeData(params: string): string {
console.info("H5传入参数:", params);
return JSON.stringify({
code: 200,
msg: "原生回调成功",
data: "来自鸿蒙原生返回数据"
});
}
}
我简单解释三个方法的定位:
-
getDeviceInfo:无参返回设备信息,最基础的同步调用
-
showNativeToast:H5 控制原生 UI 行为
-
getNativeData:H5 传参、原生处理、同步返回结果,业务最常用
三、第二步:页面注册桥接对象,开启通信能力
写好了工具类不代表能用,必须在 Web 组件初始化时 注册到 Web 内核。
核心 API:registerJavaScriptProxy
参数说明(很多人搞不懂):
-
参数1:你自定义的桥接实例对象
-
参数2:H5 全局调用的对象名(前端通过这个名字调用)
-
参数3:对外开放的方法名数组(严格白名单,不写就调用不到)
完整页面可运行代码(融合前两篇生命周期):
import { Web, WebController, WebLoadStatus, CacheMode } from '@kit.ArkWeb';
import { JsBridgeModel } from './JsBridgeModel';
@Entry
@Component
struct ArkWebBridgePage {
private webController: WebController = new WebController();
private jsBridge: JsBridgeModel = new JsBridgeModel();
@State loadStatus: string = "页面待加载";
aboutToAppear() {
// 关闭缓存,保证调试最新页面
this.webController.setCacheMode(CacheMode.None);
}
onPageShow() {
this.webController.resume();
}
onPageHide() {
this.webController.pause();
}
aboutToDisappear() {
// 页面销毁必须清空桥接引用,防止内存泄漏
this.jsBridge.h5Callback = null;
this.webController.destroy();
}
build() {
Column() {
Text(`加载状态:${this.loadStatus}`)
.fontSize(16)
.margin(12)
Web({
src: "https://xxx你的测试H5地址/index.html",
controller: this.webController
})
.width('100%')
.height('85%')
.javaScriptAccess(true) // 必须开启JS执行权限
.registerJavaScriptProxy(
this.jsBridge,
"nativeBridge",
["getDeviceInfo", "showNativeToast", "getNativeData"]
)
.onLoadStatusChange((status) => {
if (status === WebLoadStatus.StartLoading) {
this.loadStatus = "开始加载H5页面";
} else if (status === WebLoadStatus.FinishLoading) {
this.loadStatus = "页面加载完成,桥接已就绪";
} else if (status === WebLoadStatus.ErrorLoading) {
this.loadStatus = "页面加载失败";
}
})
}
.width('100%')
.height('100%')
}
}
重点踩坑提醒:
必须开启 .javaScriptAccess(true)
不开启 JS 权限,桥接直接失效,前端调用全部无响应,控制台不报错,超级难排查。

四、第三步:H5 端调用鸿蒙原生(前端标准写法)
注册完成后,前端 H5 全局会多出一个对象:nativeBridge,就是我们刚才定义的名称。
前端直接调用即可,我给你 鸿蒙ArkWeb专用、无兼容问题的前端JS代码:
// 1. H5调用原生获取设备信息
function callNativeDeviceInfo() {
let res = nativeBridge.getDeviceInfo();
console.log("原生设备信息:", JSON.parse(res));
}
// 2. H5调用原生弹窗提示
function callNativeToast() {
nativeBridge.showNativeToast("来自H5的调用提示");
}
// 3. H5传参调用原生并获取返回值
function callNativeParam() {
let result = nativeBridge.getNativeData("我是H5传给原生的参数");
console.log("原生返回结果:", JSON.parse(result));
}
调用顺序:
-
H5 页面加载完成后再调用,防止桥接未初始化
-
所有参数建议用字符串传递,复杂数据 JSON 序列化
-
返回值统一 JSON 解析,保证前后端格式统一
五、第四步:鸿蒙原生主动调用 H5 方法(反向通信)
双向通信,一定包含两个方向:
H5 调原生 +原生调 H5
场景非常多:登录成功通知 H5、退出登录清空H5状态、原生扫码结果回传给H5、推送消息刷新页面。
原生调用 H5 核心 API:runJavaScript
首先前端 H5 提前定义好全局方法:
// H5全局方法,供鸿蒙原生调用
window.getNativeNotice = function(msg){
console.log("鸿蒙原生通知H5:", msg);
alert("收到原生消息:" + msg);
}
然后鸿蒙原生直接执行:
// 原生主动推送数据给H5
sendMsgToH5(){
let params = "Hello 来自鸿蒙7原生推送";
// 执行H5全局JS方法
this.webController.runJavaScript(`getNativeNotice('${params}')`, (res) => {
console.info("调用H5方法完成,返回:", res);
})
}
这就实现了 原生主动控制H5页面。

六、高阶实战:带异步回调的完整通信方案(业务必备)
上面是同步调用,真实项目绝大多数是异步:比如 H5 调用原生扫码、原生定位、原生网络请求,耗时操作需要异步回调。
我直接给你可上线的异步桥接模板。
6.1 桥接类增加异步回调方法
@JavaScriptInterface
requestNativeAsync(msg:string):void{
// 模拟原生异步耗时操作
setTimeout(()=>{
let result = JSON.stringify({
code:200,
data:"异步任务执行成功"
})
// 回调结果给H5
if(this.h5Callback){
this.h5Callback(result);
}
},1000)
}
6.2 页面初始化监听回调
aboutToAppear(){
this.jsBridge.h5Callback = (res:string)=>{
console.info("异步回调返回H5结果:",res)
}
}
6.3 H5异步调用写法
// H5调用原生异步方法
nativeBridge.requestNativeAsync("请求原生异步任务");
至此,同步调用、异步回调、双向通信全部闭环。

七、高频踩坑汇总(全部是我实战踩过的坑)
坑1:忘记开启 javaScriptAccess(true)
表现:无报错、无响应、死活调不通。
坑2:注册方法名和H5调用名不一致
register 的白名单数组写什么,前端才能调什么,大小写严格区分。
坑3:页面不销毁桥接引用导致内存泄漏
一定要在 aboutToDisappear 清空回调、销毁 WebController。
坑4:H5加载完成前调用桥接
前端必须在 onload 之后再调用原生方法。
坑5:复杂对象直接传参
鸿蒙桥接只稳定支持字符串传参,对象必须 JSON 序列化。
八、本篇总结 + 课后实战任务
本篇我们彻底打通了 ArkWeb 混合开发的核心灵魂:双向JSBridge通信。
你现在掌握的能力:
-
正确注册 HarmonyOS7 专属 Web 桥接对象
-
H5 调用原生同步方法、获取返回值
-
H5 调用原生异步任务、接收回调结果
-
原生主动调用、通知、刷新 H5 页面
-
规避 90% 新手桥接报错、内存泄漏、调用失效问题
实操指南:
-
自己新增一个原生方法:获取APP版本号,提供给H5调用
-
实现原生按钮点击,主动给H5推送一条自定义消息
-
页面销毁前后打印日志,观察桥接引用是否清空

更多推荐




所有评论(0)