HarmonyOS中,html 与 ets 桥接沟通

引言:为什么需要桥接?在HarmonyOS的跨平台开发中,我们经常遇到这样的场景:页面中需要嵌入复杂的前端交互(如地图、图表、富文本编辑器),而这些功能在原生ETS(Enhanced TypeScript)组件中实现起来较为繁琐。此时,使用HTML5页面作为子组件,并通过桥接机制与ETS主程序通信,就成为了最佳实践。这种桥接模式允许ETS调用HTML的JavaScript函数,同时HTML也能触发ETS的事件回调,实现双向数据流动。本文将从基础概念出发,逐步深入高级用法,帮助读者掌握这一关键技术。## 基础概念:Web组件与JavaScriptProxy### 1. 第一个示例:ETS加载HTML页面首先,我们创建一个简单的ETS页面,通过Web组件加载本地HTML文件。步骤1:创建HTML文件resources/rawfile目录下创建hello.htmlhtml<!DOCTYPE html><html><body> <h1>Hello from HTML!</h1> <p id="message">等待ETS调用...</p> <script> // 暴露给ETS调用的函数 function updateMessage(text) { document.getElementById('message').innerText = text; } </script></body></html>步骤2:创建ETS页面typescript// HelloPage.etsimport { Web, webview } from '@kit.ArkUI';@Entry@Componentstruct HelloPage { @State message: string = '初始消息'; private webController: webview.WebviewController = new webview.WebviewController(); build() { Column() { Button('更新HTML消息') .onClick(() => { // 通过JavaScriptProxy调用HTML函数 this.webController.runJavaScript('updateMessage("来自ETS的问候!")'); }) Web({ src: $rawfile('hello.html'), controller: this.webController }) .width('100%') .height(300) } .width('100%') .height('100%') }}代码说明:- $rawfile引用资源文件中的HTML- Web组件作为容器加载HTML页面- webController.runJavaScript()直接执行HTML中的JavaScript函数- 这是最简单的单向调用:ETS→HTML## 进阶实践:双向桥接通信### 2. 实现HTML→ETS的回调实际开发中,HTML需要向ETS发送数据(如用户点击按钮)。这需要注册JavaScript代理对象。步骤1:创建带回调的HTMLhtml<!-- bridge_demo.html --><!DOCTYPE html><html><body> <h2>桥接通信演示</h2> <button onclick="sendToETS()">点击发送数据到ETS</button> <p>从ETS接收的数据: <span id="etsData">等待中...</span></p> <script> // 存储ETS传入的代理对象 let etsBridge = null; // 由ETS调用的初始化函数 function initBridge(bridgeObj) { etsBridge = bridgeObj; console.log('桥接初始化完成'); } // 向ETS发送数据 function sendToETS() { if (etsBridge) { const data = { type: 'buttonClick', timestamp: Date.now(), value: Math.random() }; // 调用ETS注册的回调方法 etsBridge.onHtmlEvent(JSON.stringify(data)); } } // 由ETS调用来更新页面 function updateFromETS(text) { document.getElementById('etsData').innerText = text; } </script></body></html>步骤2:创建ETS桥接类typescript// BridgeManager.etsimport { webview } from '@kit.ArkUI';// 桥接类:必须使用 @JavaScriptProxy 装饰器@JavaScriptProxyclass HtmlBridge { // 持有ETS组件的引用 private callback: (data: string) => void; constructor(callback: (data: string) => void) { this.callback = callback; } // HTML调用的方法 onHtmlEvent(data: string): void { console.log('收到HTML数据:', data); if (this.callback) { this.callback(data); } }}步骤3:主ETS页面typescript// MainPage.etsimport { Web, webview } from '@kit.ArkUI';@Entry@Componentstruct MainPage { @State receivedData: string = ''; private webController: webview.WebviewController = new webview.WebviewController(); private bridge: HtmlBridge = new HtmlBridge((data) => { // 处理HTML回调 this.receivedData = data; console.log('桥接回调触发'); }); build() { Column() { Text('接收自HTML的数据:') .fontSize(18) Text(this.receivedData) .fontSize(14) .margin({ top: 10 }) Button('发送数据到HTML') .onClick(() => { // 调用HTML函数 this.webController.runJavaScript( `updateFromETS('Hello from ETS at ${new Date().toLocaleTimeString()}')` ); }) Web({ src: $rawfile('bridge_demo.html'), controller: this.webController }) .width('100%') .height(400) .onPageEnd(() => { // 页面加载完成后,注册JavaScript代理 this.webController.registerJavaScriptProxy( this.bridge, // 代理对象 'etsBridge', // HTML中的变量名 ['onHtmlEvent'] // 暴露的方法列表 ); // 调用HTML的初始化函数 this.webController.runJavaScript('initBridge(etsBridge)'); }) } .width('100%') .height('100%') .padding(20) }}代码说明:- @JavaScriptProxy装饰器标记桥接类- registerJavaScriptProxy将ETS对象暴露给HTML- onPageEnd事件确保页面加载完成后再注册代理- 实现了完整的双向通信:ETS→HTML(runJavaScript)和HTML→ETS(代理回调)## 高级技巧:参数传递与安全控制### 3. 复杂数据交换与权限管理在实际项目中,我们可能需要传递复杂对象,并控制哪些方法可以被HTML调用。高级桥接类示例:typescript// AdvancedBridge.ets@JavaScriptProxyclass AdvancedBridge { private etsContext: object; private allowedMethods: Set<string> = new Set(['getData', 'log', 'triggerEvent']); constructor(context: object) { this.etsContext = context; } // 权限校验:只暴露允许的方法 getData(key: string): string { if (!this.allowedMethods.has('getData')) { return '无权限'; } // 从ETS上下文获取数据 return `获取 ${key} 数据成功`; } // 日志记录(HTML调用进行日志上报) log(level: string, message: string): void { console.log(`[HTML-${level}] ${message}`); } // 触发ETS事件 triggerEvent(eventName: string, payload: string): void { if (this.allowedMethods.has('triggerEvent')) { // 分发事件到ETS (this.etsContext as any).handleEvent(eventName, JSON.parse(payload)); } }}**安全注意事项:**1. 始终在onPageEnd回调中注册代理,避免页面未就绪时调用2. 对HTML输入进行验证(如JSON.parse前的try-catch)3. 使用白名单机制控制暴露的方法4. 避免在HTML中直接访问敏感API## 性能优化与最佳实践### 4. 大量数据传递优化当需要传递大量数据(如日志记录、实时数据流)时,建议:1. 使用批处理:将多次小数据合并为一次传递2. 采用JSON序列化:避免频繁的字符串拼接3. 异步处理:使用Web Worker避免阻塞UI线程typescript// 批量数据传递示例const batchData = [];for (let i = 0; i < 1000; i++) { batchData.push({ id: i, value: Math.random() });}// 压缩后传递webController.runJavaScript(`processBatch('${JSON.stringify(batchData)}')`);## 总结本文从零开始,逐步构建了HarmonyOS中HTML与ETS的完整桥接通信方案:1. 基础篇:通过runJavaScript实现了ETS调用HTML函数2. 进阶篇:通过registerJavaScriptProxy@JavaScriptProxy装饰器实现了双向通信3. 高级篇:讨论了复杂数据传递、权限控制和安全优化核心要点:- Web组件是桥接的载体- JavaScriptProxy是实现HTML→ETS回调的关键- 始终在页面加载完成(onPageEnd)后进行代理注册- 注意数据序列化和安全校验通过这种桥接机制,开发者可以充分利用HTML5生态的丰富组件,同时保留ETS原生应用的性能和系统能力,实现真正的跨平台高效开发。

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐