鸿蒙ArkTS与H5双向通信实战:从原理到可运行案例,一文吃透
在鸿蒙HarmonyOS原生开发中,ArkTS作为主力开发语言,经常需要与H5页面进行交互——比如原生应用内嵌H5网页、H5调用鸿蒙系统能力(如获取设备信息、弹窗提示)、ArkTS向H5传递数据(如用户信息、配置参数)。
很多开发者在做混合开发时,会遇到“通信失败”“参数传不过去”“回调无响应”等问题,核心原因是没掌握鸿蒙官方推荐的通信方式,以及两端交互的细节规范。
本文将从「通信原理」入手,拆解ArkTS与H5双向通信的两种核心方式,提供可直接复制、跑通无压力的完整案例(含ArkTS代码+HTML代码),兼顾新手友好性和实战性,看完就能落地。
一、先搞懂:ArkTS与H5通信的核心原理
ArkTS与H5通信,本质是通过「Web组件」作为桥梁,实现两个环境的数据流转。鸿蒙官方提供了两种主流通信方式,覆盖不同开发场景:
JS注入(registerJavaScriptProxy):ArkTS向H5注入一个全局JS对象,H5直接调用该对象的方法,实现「H5→ArkTS」的通信(最常用、最简洁);
脚本执行(runJavaScript):ArkTS主动执行H5页面中的JS函数,实现「ArkTS→H5」的通信;
补充:鸿蒙Web组件支持通过MessagePorts实现更灵活的双向异步通信,但对于大部分业务场景,上述两种方式已足够覆盖,且上手更简单。本文重点讲解最常用的「JS注入+脚本执行」组合,兼顾实用性和易操作性。
核心前提:H5页面必须通过Web组件加载(本地H5/在线H5均可),且只有trustedurl中链接或src链接的网页,才能和ArkTS框架进行双向通信。
二、实战准备:环境与目录结构
1. 环境要求
2. 目录结构(关键)
我们采用「本地H5」的方式(无需联网,更易测试),目录结构如下(重点关注rawfile文件夹):
entry├─ src/main│ ├─ ets # ArkTS代码目录│ │ └─ pages│ │ └─ Index.ets # 主页面(含Web组件)│ └─ resources # 资源目录│ └─ rawfile # 存放本地H5文件(必须叫这个名字)│ ├─ index.html # H5页面│ └─ js│ └─ index.js # H5交互逻辑└─ build.gradle # 项目配置(无需修改)
注意:rawfile是鸿蒙规定的本地静态资源目录,用于存放HTML、JS、CSS等文件,Web组件可直接通过$rawfile('xxx.html')访问,无需配置额外路径。
三、完整可运行案例:双向通信实战
本次案例实现3个核心功能(覆盖日常开发80%场景):
ArkTS → H5:传递用户信息(对象类型),H5接收后展示;
H5 → ArkTS:调用鸿蒙系统弹窗(showToast),传递字符串参数;
H5 → ArkTS:调用鸿蒙方法,获取返回值(如设备类型),并在H5展示。
第一步:编写H5页面(rawfile目录下)
先创建2个文件:index.html(页面结构)和js/index.js(交互逻辑),代码可直接复制。
1. index.html(页面结构)
<!DOCTYPE html><htmllang="zh-CN"><head> <metacharset="UTF-8"> <metaname="viewport"content="width=device-width, initial-scale=1.0"> <title>ArkTS与H5通信测试</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; } body { padding: 20px; font-size: 16px; line-height: 1.5; } .container { max-width: 400px; margin: 0 auto; } .title { text-align: center; color: #2f54eb; margin-bottom: 30px; } .btn { display: block; width: 100%; padding: 12px 0; background: #2f54eb; color: #fff; border: none; border-radius: 8px; margin: 15px 0; font-size: 16px; cursor: pointer; } .info { margin: 20px 0; padding: 15px; border: 1px solid #eee; border-radius: 8px; } .info-title { font-weight: 600; margin-bottom: 10px; color: #333; } </style></head><body> <divclass="container"> <h1class="title">ArkTS ↔ H5 通信测试</h1> <!-- ArkTS传递给H5的信息展示 --> <divclass="info"> <divclass="info-title">ArkTS传递的用户信息:</div> <divid="userInfo">等待接收数据...</div> </div> <!-- H5调用ArkTS方法的按钮 --> <buttonclass="btn"onclick="callArkTSShowToast()">H5调用ArkTS弹窗</button> <buttonclass="btn"onclick="callArkTSGetDevice()">H5调用ArkTS获取设备类型</button> <!-- H5接收ArkTS返回值展示 --> <divclass="info"> <divclass="info-title">ArkTS返回的设备信息:</div> <divid="deviceInfo">未调用...</div> </div> </div> <!-- 引入交互逻辑JS --> <scriptsrc="./js/index.js"></script></body></html>
2. js/index.js(H5交互逻辑)
// 1. 接收ArkTS传递的用户信息(ArkTS主动调用此方法)function receiveUserInfo(user) { const userInfoDom = document.getElementById('userInfo'); // 格式化显示对象数据 userInfoDom.innerText = `姓名:${user.name}\n年龄:${user.age}\n手机号:${user.phone}`;}// 2. H5调用ArkTS的showToast方法(无返回值)function callArkTSShowToast() { // harmonyBridge是ArkTS注入的全局对象(名称可自定义) if (window.harmonyBridge) { // 调用ArkTS的showToast方法,传递参数 window.harmonyBridge.showToast('H5调用了ArkTS的弹窗'); } else { alert('未检测到ArkTS注入的对象,请检查配置'); }}// 3. H5调用ArkTS的getDeviceType方法(有返回值,用回调接收)function callArkTSGetDevice() { if (window.harmonyBridge) { // 调用ArkTS方法,通过回调接收返回值 window.harmonyBridge.getDeviceType((deviceType) => { const deviceInfoDom = document.getElementById('deviceInfo'); deviceInfoDom.innerText = deviceType; }); } else { alert('未检测到ArkTS注入的对象,请检查配置'); }}
第二步:编写ArkTS页面(Index.ets)
这是核心页面,负责加载H5、注入JS对象、实现与H5的双向通信,代码含详细注释,可直接复制运行。
// 导入所需模块(Web组件、弹窗、设备信息)import { webview } from '@kit.ArkWeb';import { promptAction } from '@kit.ArkUI';import deviceInfo from '@ohos.deviceInfo';@Entry@Componentstruct H5CommunicationPage { // 1. 创建Web组件控制器(用于操作Web组件,如注入JS、执行脚本) private webController: webview.WebviewController = new webview.WebviewController(); // 2. 定义要注入到H5的对象(H5通过window.harmonyBridge调用此对象的方法) private harmonyBridge = { // 方法1:H5调用此方法,显示鸿蒙系统弹窗 showToast: (message: string) => { promptAction.showToast({ message: message, duration: 2000 // 弹窗显示时间(毫秒) }); }, // 方法2:H5调用此方法,获取设备类型(返回值通过回调传递) getDeviceType: (callback: (deviceType: string) => void) => { // 获取设备类型(phone/tablet等),通过回调返回给H5 const type = deviceInfo.deviceType === 'phone' ? '手机' : '平板'; callback(`当前设备:${type}(鸿蒙系统)`); } }; build() { Column({ space: 10 }) { // 标题 Text('ArkTS与H5双向通信实战') .fontSize(22) .fontWeight(600) .margin({ top: 20, bottom: 10 }) .textAlign(TextAlign.Center); // 3. Web组件:加载本地H5页面 Web({ src: $rawfile('index.html'), // 加载rawfile目录下的index.html controller: this.webController // 绑定控制器 }) .width('100%') .height('70%') // 关键:允许H5执行JS脚本(必须开启,否则通信失败) .javaScriptEnabled(true) // 关键:注入JS对象到H5(window.harmonyBridge) .javaScriptProxy({ object: this.harmonyBridge, // 要注入的对象 name: 'harmonyBridge', // H5中访问的对象名称(自定义) methodList: ['showToast', 'getDeviceType'], // 允许H5调用的方法列表 controller: this.webController }) // Web组件加载完成后,向H5传递数据 .onPageEnd((event) => { // 4. ArkTS主动调用H5的receiveUserInfo方法,传递用户信息(对象类型) const userInfo = { name: '鸿蒙开发者', age: 25, phone: '13800138000' }; // 执行H5的JS方法,传递参数(需将对象转为字符串) this.webController.runJavaScript(`receiveUserInfo(${JSON.stringify(userInfo)})`); }); // 按钮:ArkTS主动向H5发送消息(可选,补充场景) Button('ArkTS向H5发送消息') .width('80%') .height(45) .backgroundColor('#2f54eb') .fontColor('#fff') .borderRadius(8) .onClick(() => { // 调用H5的receiveUserInfo方法,传递新数据 const newUser = { name: '新用户', age: 30, phone: '13900139000' }; this.webController.runJavaScript(`receiveUserInfo(${JSON.stringify(newUser)})`); }); } .width('100%') .height('100%') .backgroundColor('#f5f5f5'); }}
第三步:运行测试(关键步骤)
将上述代码复制到对应目录,保存项目;
选择模拟器(API 10)或鸿蒙真机,点击「运行」按钮;
运行成功后,会看到如下效果:
页面加载完成后,H5自动显示ArkTS传递的用户信息;
点击「H5调用ArkTS弹窗」,鸿蒙系统会弹出提示;
点击「H5调用ArkTS获取设备类型」,H5会显示当前设备信息;
点击「ArkTS向H5发送消息」,H5会更新显示新的用户信息。
测试验证:所有操作均能正常响应,说明双向通信成功。若出现失败,可查看下方「避坑指南」。
四、关键细节与避坑指南(必看)
很多开发者复制代码后跑不通,大多是忽略了以下细节,建议逐一检查:
1. 必须开启JavaScriptEnabled
Web组件必须设置javaScriptEnabled(true),否则H5无法执行JS脚本,也无法调用ArkTS注入的对象,通信直接失败。
2. 注入对象的方法列表必须完整
javaScriptProxy的methodList数组,必须包含H5要调用的所有方法(如案例中的['showToast', 'getDeviceType']),否则H5调用时会提示“方法不存在”。
3. 传递对象参数需序列化
ArkTS向H5传递对象、数组等复杂类型时,必须用JSON.stringify()转为字符串,H5接收后可根据需求用JSON.parse()解析(案例中H5直接使用,因JS自动解析了字符串对象)。
4. 回调函数的使用规范
H5调用ArkTS方法并需要返回值时,必须用「回调函数」接收(如案例中的getDeviceType方法),不能直接用return返回——因为H5与ArkTS通信是异步的,直接return无法获取到返回值。
5. 本地H5路径必须正确
Web组件加载本地H5时,src必须是$rawfile('index.html'),且H5文件必须放在resources/rawfile目录下(目录名称不能错),否则会出现“页面加载失败”。
6. 版本兼容性
本文案例基于API 10(HarmonyOS NEXT),若使用API 9及以下版本,部分API会有差异(如webview模块的导入方式),建议升级到API 10开发,避免兼容性问题。
五、拓展场景:在线H5与ArkTS通信
若你的H5是在线页面(如https://xxx.com/h5),只需修改Web组件的src路径,其余代码不变:
Web({ src: 'https://xxx.com/h5', // 在线H5地址 controller: this.webController}).javaScriptEnabled(true).javaScriptProxy({ object: this.harmonyBridge, name: 'harmonyBridge', methodList: ['showToast', 'getDeviceType'], controller: this.webController})
注意:在线H5必须是可信链接(trustedurl),否则可能无法与ArkTS通信,具体可参考鸿蒙官方文档配置可信链接。
六、总结
ArkTS与H5双向通信的核心,是通过Web组件搭建桥梁,用「JS注入」实现H5调用ArkTS,用「脚本执行」实现ArkTS调用H5,两者结合可覆盖所有混合开发场景。
本文提供的案例是最通用、最易落地的实现方式,代码可直接复制跑通,新手也能快速上手。关键是记住3个核心点:开启JS权限、正确注入对象、规范传递参数。
如果需要更复杂的通信场景(如二进制数据传递、频繁消息交互),可以尝试鸿蒙的MessagePorts通信方式,其支持更灵活的双向异步交互,适合复杂业务场景。
福利:本文案例完整源码(含ArkTS+HTML+JS),可直接复制到项目中运行,无需额外修改。为方便大家快速使用,整理了源码压缩包说明,步骤如下:
新建压缩包,命名为「ArkTS-H5通信案例源码」;
按本文目录结构,创建entry、src/main/ets/pages、src/main/resources/rawfile、src/main/resources/rawfile/js目录;
将本文中的Index.ets、index.html、index.js代码分别复制到对应目录下;
压缩后直接导入DevEco Studio,无需修改任何配置,即可运行测试。
看完本文,你已经掌握了ArkTS与H5通信的核心技巧,快去动手实践吧!
关注我,解锁更多鸿蒙原生开发实战技巧 🚀