写点什么

【HarmonyOS 5】鸿蒙 Web 组件和内嵌网页双向通信 DEMO 示例

作者:GeorgeGcs
  • 2025-05-08
    上海
  • 本文字数:4402 字

    阅读完需:约 14 分钟

【HarmonyOS 5】鸿蒙Web组件和内嵌网页双向通信DEMO示例

删除线格式 ## 【HarmonyOS 5】鸿蒙 Web 组件和内嵌网页双向通信 DEMO 示例

一、前言

在 ArkUI 开发中,Web 组件(Web)允许开发者在应用内嵌入网页,实现混合开发场景。


本文将通过完整 DEMO,详解如何通过 WebviewController 实现 ArkUI 与内嵌网页的双向通信,涵盖 ArkUI 调用网页 JS、网页调用 ArkUI 对象的核心技术点。

二、双向通信实现原理

1、双向通信概念 Web 到 ArkUI(反向通信)通过 registerJavaScriptProxy 将 ArkUI 对象注册到网页的 window 对象,允许网页通过 window.xxx 调用 ArkUI 暴露的方法。​


ArkUI 到 Web(正向通信)通过 runJavaScript 执行网页 JS 代码,支持回调获取返回值,实现原生代码调用网页函数。


2、双向通信流程图 ArkUI Web┌──────────────┐ ┌──────────────┐│ registerJS ├─────────────▶ window.objName ││ (反向注册) │ ├──────────────┤├──────────────┤ │ call test() ││ runJavaScript├─────────────▶ execute JS code ││ (正向调用) │ ├──────────────┤└──────────────┘ └──────────────┘

三、双向通信实现步骤

1、ArkUI 定义可被网页调用的对象创建一个 TestObj 类,声明允许网页调用的方法(白名单机制):


class TestObj {  // 网页可调用的方法1:返回字符串  test(): string {    return "ArkUI Web Component";  }
// 网页可调用的方法2:打印日志 toString(): void { console.log('Web Component toString'); }
// 网页可调用的方法3:接收网页消息 receiveMessageFromWeb(message: string): void { console.log(`Received from web: ${message}`); }}
复制代码


2、ArkUI 组件核心代码初始化控制器与状态


@Entry@Componentstruct WebComponent {  // Webview控制器  controller: webview.WebviewController = new webview.WebviewController();  // 注册到网页的ArkUI对象  @State testObj: TestObj = new TestObj();  // 注册名称(网页通过window.[name]访问)  @State regName: string = 'objName';  // 接收网页返回数据  @State webResult: string = '';
build() { /* 组件布局与交互逻辑 */ }}
复制代码


布局与交互按钮,添加三个核心功能按钮:


Column() {  // 显示网页返回数据  Text(`Web返回数据:${this.webResult}`).fontSize(16).margin(10);
// 1. 注册ArkUI对象到网页 Button('注册到Window') .onClick(() => { this.controller.registerJavaScriptProxy( this.testObj, // ArkUI对象 this.regName, // 网页访问名称 ["test", "toString", "receiveMessageFromWeb"] // 允许调用的方法白名单 ); })
// 2. ArkUI调用网页JS Button('调用网页函数') .onClick(() => { this.controller.runJavaScript( 'webFunction("Hello from ArkUI!")', // 执行网页JS代码 (error, result) => { // 回调处理返回值 if (!error) this.webResult = result || '无返回值'; } ); })
// 3. Web组件加载 Web({ src: $rawfile('index.html'), controller: this.controller }) .javaScriptAccess(true) // 开启JS交互权限 .onPageEnd(() => { // 页面加载完成时触发 // 页面加载后自动调用网页测试函数 this.controller.runJavaScript('initWebData()'); })}
复制代码


3. registerJavaScriptProxy 的实际作用是,将 ArkUI 对象绑定到网页 window,实现反向通信。


registerJavaScriptProxy(  obj: Object,        // ArkUI中定义的对象  name: string,       // 网页访问的名称(如window.name)  methods: string[]   // 允许调用的方法白名单(严格匹配方法名));
复制代码

源码示例

完整代码已上传至 Gitee 仓库,欢迎下载调试!如果有任何问题,欢迎在评论区留言交流~


项目结构├── xxx.ets # ArkUI 组件代码└── index.html # 内嵌网页文件



WebViewPage.ets


import { webview } from '@kit.ArkWeb';import { BusinessError } from '@kit.BasicServicesKit';
class TestObj { constructor() { }
test(): string { return "ArkUI Web Component"; }
toString(): void { console.log('Web Component toString'); }
receiveMessageFromWeb(message: string): void { console.log(`Received message from web: ${message}`); }}
@Entry@Componentstruct WebViewPage { controller: webview.WebviewController = new webview.WebviewController(); @State testObjtest: TestObj = new TestObj(); @State name: string = 'objName'; @State webResult: string = '';
build() { Column() { Text(this.webResult).fontSize(20) Button('refresh') .onClick(() => { try { this.controller.refresh(); } catch (error) { console.error(`ErrorCode: ${(error as BusinessError).code}, Message: ${(error as BusinessError).message}`); } }) Button('Register JavaScript To Window') .onClick(() => { try { this.controller.registerJavaScriptProxy(this.testObjtest, this.name, ["test", "toString", "receiveMessageFromWeb"]); } catch (error) { console.error(`ErrorCode: ${(error as BusinessError).code}, Message: ${(error as BusinessError).message}`); } }) Button('deleteJavaScriptRegister') .onClick(() => { try { this.controller.deleteJavaScriptRegister(this.name); } catch (error) { console.error(`ErrorCode: ${(error as BusinessError).code}, Message: ${(error as BusinessError).message}`); } }) Button('Send message to web') .onClick(() => { try { this.controller.runJavaScript( 'receiveMessageFromArkUI("Hello from ArkUI!")', (error, result) => { if (error) { console.error(`run JavaScript error, ErrorCode: ${(error as BusinessError).code}, Message: ${(error as BusinessError).message}`); return; } console.info(`Message sent to web result: ${result}`); } ); } catch (error) { console.error(`ErrorCode: ${(error as BusinessError).code}, Message: ${(error as BusinessError).message}`); } }) Button('Get data from web') .onClick(() => { try { this.controller.runJavaScript( 'getWebPageData()', (error, result) => { if (error) { console.error(`run JavaScript error, ErrorCode: ${(error as BusinessError).code}, Message: ${(error as BusinessError).message}`); return; } if (result) { this.webResult = result; console.info(`Data from web: ${result}`); } } ); } catch (error) { console.error(`ErrorCode: ${(error as BusinessError).code}, Message: ${(error as BusinessError).message}`); } }) Web({ src: $rawfile('index.html'), controller: this.controller }) .javaScriptAccess(true) .onPageEnd(e => { try { this.controller.runJavaScript( 'test()', (error, result) => { if (error) { console.error(`run JavaScript error, ErrorCode: ${(error as BusinessError).code}, Message: ${(error as BusinessError).message}`); return; } if (result) { this.webResult = result; console.info(`The test() return value is: ${result}`); } } ); if (e) { console.info('url: ', e.url); } } catch (error) { console.error(`ErrorCode: ${(error as BusinessError).code}, Message: ${(error as BusinessError).message}`); } }) .width("100%") .height("50%") } .width("100%") .height("100%") .backgroundColor(Color.Black) }}
复制代码


index.html


<!DOCTYPE html><html lang="en">
<head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Web Communication</title></head>
<body><button onclick="callArkUIMethod()">Call ArkUI Method</button><button onclick="sendMessageToArkUI()">Send message to ArkUI</button><div id="messageFromArkUI"></div><script> function callArkUIMethod() { const result = window.objName.test(); console.log("Result from ArkUI: ", result); }
function sendMessageToArkUI() { window.objName.receiveMessageFromWeb('Hello from web!'); }
function receiveMessageFromArkUI(message) { const messageDiv = document.getElementById('messageFromArkUI'); messageDiv.textContent = `Received message from ArkUI: ${message}`; }
function getWebPageData() { return "Data from web page"; }
function test() { return "Test function result from web"; }</script></body>
</html>
复制代码

注意

组件销毁时调用 deleteJavaScriptRegister(name)取消注册,避免内存泄漏:


onDestroy() {  this.controller.deleteJavaScriptRegister(this.regName);}
复制代码


发布于: 刚刚阅读数: 7
用户头像

GeorgeGcs

关注

路漫漫其修远兮,吾将上下而求索。 2024-12-24 加入

历经腾讯,宝马,研究所,金融。 待过私企,外企,央企。 深耕大应用开发领域十年。 OpenHarmony,HarmonyOS,Flutter,H5,Android,IOS。 目前任职鸿蒙应用架构师。 HarmonyOS官方认证创作先锋,华为开发专家HDE。

评论

发布
暂无评论
【HarmonyOS 5】鸿蒙Web组件和内嵌网页双向通信DEMO示例_GeorgeGcs_InfoQ写作社区