【HarmonyOS 5】鴻蒙Web組件和內(nèi)嵌網(wǎng)頁雙向通信DEMO示例
##鴻蒙開發(fā)能力 ##HarmonyOS SDK應(yīng)用服務(wù)##鴻蒙金融類應(yīng)用 (金融理財(cái)#
一、前言
在 ArkUI 開發(fā)中,Web 組件(Web)允許開發(fā)者在應(yīng)用內(nèi)嵌入網(wǎng)頁,實(shí)現(xiàn)混合開發(fā)場景。
本文將通過完整 DEMO,詳解如何通過WebviewController實(shí)現(xiàn) ArkUI 與內(nèi)嵌網(wǎng)頁的雙向通信,涵蓋 ArkUI 調(diào)用網(wǎng)頁 JS、網(wǎng)頁調(diào)用 ArkUI 對象的核心技術(shù)點(diǎn)。
二、雙向通信實(shí)現(xiàn)原理
1、雙向通信概念
Web 到 ArkUI(反向通信)通過registerJavaScriptProxy將 ArkUI 對象注冊到網(wǎng)頁的window對象,允許網(wǎng)頁通過window.xxx調(diào)用 ArkUI 暴露的方法。?
ArkUI 到 Web(正向通信)通過runJavaScript執(zhí)行網(wǎng)頁 JS 代碼,支持回調(diào)獲取返回值,實(shí)現(xiàn)原生代碼調(diào)用網(wǎng)頁函數(shù)。
2、雙向通信流程圖
ArkUI Web
┌──────────────┐ ┌──────────────┐
│ registerJS ├─────────────? window.objName │
│ (反向注冊) │ ├──────────────┤
├──────────────┤ │ call test() │
│ runJavaScript├─────────────? execute JS code │
│ (正向調(diào)用) │ ├──────────────┤
└──────────────┘ └──────────────┘
三、雙向通信實(shí)現(xiàn)步驟
1、ArkUI 定義可被網(wǎng)頁調(diào)用的對象
創(chuàng)建一個TestObj類,聲明允許網(wǎng)頁調(diào)用的方法(白名單機(jī)制):
class TestObj {
// 網(wǎng)頁可調(diào)用的方法1:返回字符串
test(): string {
return "ArkUI Web Component";
}
// 網(wǎng)頁可調(diào)用的方法2:打印日志
toString(): void {
console.log('Web Component toString');
}
// 網(wǎng)頁可調(diào)用的方法3:接收網(wǎng)頁消息
receiveMessageFromWeb(message: string): void {
console.log(`Received from web: ${message}`);
}
}
2、ArkUI 組件核心代碼
初始化控制器與狀態(tài)
@Entry
@Component
struct WebComponent {
// Webview控制器
controller: webview.WebviewController = new webview.WebviewController();
// 注冊到網(wǎng)頁的ArkUI對象
@State testObj: TestObj = new TestObj();
// 注冊名稱(網(wǎng)頁通過window.[name]訪問)
@State regName: string = 'objName';
// 接收網(wǎng)頁返回?cái)?shù)據(jù)
@State webResult: string = '';
build() { /* 組件布局與交互邏輯 */ }
}
布局與交互按鈕,添加三個核心功能按鈕:
Column() {
// 顯示網(wǎng)頁返回?cái)?shù)據(jù)
Text(`Web返回?cái)?shù)據(jù):${this.webResult}`).fontSize(16).margin(10);
// 1. 注冊ArkUI對象到網(wǎng)頁
Button('注冊到Window')
.onClick(() = > {
this.controller.registerJavaScriptProxy(
this.testObj, // ArkUI對象
this.regName, // 網(wǎng)頁訪問名稱
["test", "toString", "receiveMessageFromWeb"] // 允許調(diào)用的方法白名單
);
})
// 2. ArkUI調(diào)用網(wǎng)頁JS
Button('調(diào)用網(wǎng)頁函數(shù)')
.onClick(() = > {
this.controller.runJavaScript(
'webFunction("Hello from ArkUI!")', // 執(zhí)行網(wǎng)頁JS代碼
(error, result) = > { // 回調(diào)處理返回值
if (!error) this.webResult = result || '無返回值';
}
);
})
// 3. Web組件加載
Web({ src: $rawfile('index.html'), controller: this.controller })
.javaScriptAccess(true) // 開啟JS交互權(quán)限
.onPageEnd(() = > { // 頁面加載完成時觸發(fā)
// 頁面加載后自動調(diào)用網(wǎng)頁測試函數(shù)
this.controller.runJavaScript('initWebData()');
})
}
3. registerJavaScriptProxy的實(shí)際作用是,將 ArkUI 對象綁定到網(wǎng)頁window,實(shí)現(xiàn)反向通信。
registerJavaScriptProxy(
obj: Object, // ArkUI中定義的對象
name: string, // 網(wǎng)頁訪問的名稱(如window.name)
methods: string[] // 允許調(diào)用的方法白名單(嚴(yán)格匹配方法名)
);
源碼示例
完整代碼已上傳至Gitee 倉庫,歡迎下載調(diào)試!如果有任何問題,歡迎在評論區(qū)留言交流~
項(xiàng)目結(jié)構(gòu)
├── xxx.ets # ArkUI組件代碼
└── index.html # 內(nèi)嵌網(wǎng)頁文件
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
@Component
struct 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 >
"callArkUIMethod()"< /span?> >Call ArkUI Method< /button >
"sendMessageToArkUI()"< /span?> >Send message to ArkUI< /button >
"messageFromArkUI">
< 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 >
注意
組件銷毀時調(diào)用deleteJavaScriptRegister(name)取消注冊,避免內(nèi)存泄漏:
onDestroy() {
this.controller.deleteJavaScriptRegister(this.regName);
}
審核編輯 黃宇
-
鴻蒙
+關(guān)注
關(guān)注
60文章
2620瀏覽量
44063 -
HarmonyOS
+關(guān)注
關(guān)注
80文章
2126瀏覽量
33092
發(fā)布評論請先 登錄
鴻蒙OS開發(fā)實(shí)例:【Web網(wǎng)頁】

鴻蒙開發(fā)基礎(chǔ)-Web組件之cookie操作
tcp/ip雙向通信
NRF2401無線模塊的雙向通信怎么實(shí)現(xiàn)?
HarmonyOS/OpenHarmony應(yīng)用開發(fā)-Web組件開發(fā)體驗(yàn)
HarmonyOS—使用Web組件加載頁面
具有雙向通信功能的標(biāo)準(zhǔn)源
【HarmonyOS 5】鴻蒙頁面和組件生命周期函數(shù)
【HarmonyOS 5】鴻蒙星閃NearLink詳解

【HarmonyOS 5】金融應(yīng)用開發(fā)鴻蒙組件實(shí)踐

【 HarmonyOS 5 入門系列 】鴻蒙HarmonyOS示例項(xiàng)目講解

評論