Web组件集成:加载网页与JS交互(JavascriptProxy)(34)
在 HarmonyOS 的 ArkUI 开发中Web 组件是实现混合开发Hybrid的核心。通过 Web 组件开发者可以在应用内无缝嵌入网页并通过 JSBridge 实现原生端ArkTS与前端H5的双向通信。以下是 Web 组件集成与 JS 交互一、 Web 组件的四种加载方式Web 组件支持多种数据来源以适应不同的业务场景加载在线 URLWeb({ src: https://... })适用于加载网络页面。注意需在module.json5中申请ohos.permission.INTERNET权限。加载本地 rawfileWeb({ src: $rawfile(index.html) })适用于加载打包在src/main/resources/rawfile/目录下的本地 HTML 文件。resource 协议Web({ src: resource://rawfile/index.html })适用于运行时动态指定本地文件路径。loadData 渲染字符串通过controller.loadData(htmlStr, ...)直接渲染 HTML 字符串适用于加载富文本数据。import { webview } from kit.ArkWeb; import { BusinessError } from kit.BasicServicesKit; Entry Component struct WebLoadDemo { controller: webview.WebviewController new webview.WebviewController(); // 用于 loadData 渲染的 HTML 字符串 State htmlContent: string !DOCTYPE html htmlheadtitle动态内容/title/head body h1 stylecolor: #007AFF;这是动态生成的内容/h1 p无需任何文件直接渲染字符串/p /body/html; build() { Column() { Text(Web 组件四种加载方式演示) .fontSize(20) .fontWeight(FontWeight.Bold) .margin({ bottom: 10 }) Row({ space: 10 }) { // 方式一加载在线 URL Button(加载在线URL) .onClick(() { try { this.controller.loadUrl(https://developer.huawei.com/); } catch (error) { console.error(ErrorCode: ${(error as BusinessError).code}, Message: ${(error as BusinessError).message}); } }) // 方式二加载本地 rawfile Button(加载本地Rawfile) .onClick(() { try { this.controller.loadUrl($rawfile(index.html)); } catch (error) { console.error(ErrorCode: ${(error as BusinessError).code}, Message: ${(error as BusinessError).message}); } }) // 方式三使用 resource 协议 Button(Resource协议) .onClick(() { try { this.controller.loadUrl(resource://rawfile/index.html); } catch (error) { console.error(ErrorCode: ${(error as BusinessError).code}, Message: ${(error as BusinessError).message}); } }) // 方式四loadData 渲染字符串 Button(LoadData渲染) .onClick(() { try { this.controller.loadData( this.htmlContent, text/html, // mimeType UTF-8 // encoding ); } catch (error) { console.error(ErrorCode: ${(error as BusinessError).code}, Message: ${(error as BusinessError).message}); } }) } .margin({ bottom: 10 }) // Web 组件初始化默认加载本地页面 Web({ src: $rawfile(index.html), controller: this.controller }) .width(100%) .layoutWeight(1) .javaScriptAccess(true) .domStorageAccess(true) } .width(100%) .height(100%) .padding(20) } }代码要点解析加载在线 URL点击按钮后通过controller.loadUrl()加载华为开发者官网。注意需在module.json5中添加网络权限requestPermissions: [{ name: ohos.permission.INTERNET }]加载本地 rawfile使用$rawfile(index.html)静态引用指向src/main/resources/rawfile/index.html。该方式支持在 HTML 中正常引用同目录下的 CSS、JS、图片等资源。resource 协议使用resource://rawfile/index.html字符串格式与$rawfile()指向同一目录但它是纯字符串可以在运行时动态拼接和构造路径。loadData 渲染字符串无需任何文件直接将 HTML 内容作为字符串传入controller.loadData()进行渲染。适合做富文本邮件、协议弹窗、动态内容展示等场景。二、 ArkUI 与 Web 的双向通信机制双向通信是 Hybrid 开发的基石主要分为“正向调用”和“反向注入”两个方向1. 正向通信ArkUI 调用 Web (runJavaScript)原生端通过WebviewController的runJavaScript方法可以直接执行网页中的 JS 代码并支持通过回调获取返回值。this.controller.runJavaScript(webFunction(Hello from ArkUI!), (error, result) { if (!error) { console.info(Web返回数据 result); } });注意该方法必须在页面加载完成后调用如在onPageEnd回调中否则可能执行失败。2. 反向通信Web 调用 ArkUI (JavaScriptProxy)这是最核心的 JSBridge 实现方式。通过javaScriptProxy将 ArkUI 对象注入到 Webview 的window对象中前端即可像调用本地方法一样调用原生能力。ArkTS 侧代码// 1. 定义原生对象 class NativeObj { makePhoneCall(number: string): void { console.info(准备拨打电话 number); } } // 2. 在 Web 组件中注入 Web({ src: $rawfile(index.html), controller: this.controller }) .javaScriptProxy({ object: new NativeObj(), name: native, // 前端通过 window.native 访问 methodList: [makePhoneCall], // 允许调用的方法白名单 controller: this.controller })Web (JS) 侧调用window.native.makePhoneCall(10086);三、 动态注册与注销除了初始化时静态注入ArkUI 还支持在运行时动态管理注入对象动态注册使用controller.registerJavaScriptProxy(obj, name, methods)。刷新生效动态注册后必须执行controller.refresh()刷新页面注入才会生效注销对象使用controller.deleteJavaScriptRegister(name)移除已注入的对象。ArkTS 侧代码import { webview } from kit.ArkWeb; import { BusinessError } from kit.BasicServicesKit; // 1. 定义需要注入到前端的原生对象 class NativeBridge { sayHello(): string { return Hello from ArkTS Dynamic Proxy!; } } Entry Component struct DynamicProxyDemo { controller: webview.WebviewController new webview.WebviewController(); State bridgeObj: NativeBridge new NativeBridge(); build() { Column() { Row({ space: 10 }) { // 2. 动态注册按钮 Button(动态注册) .onClick(() { try { this.controller.registerJavaScriptProxy( this.bridgeObj, nativeBridge, // 前端访问的对象名 [sayHello] // 允许调用的方法白名单 ); // ⚠️ 核心步骤动态注册后必须刷新页面才能生效 this.controller.refresh(); } catch (error) { console.error(ErrorCode: ${(error as BusinessError).code}, Message: ${(error as BusinessError).message}); } }) // 3. 注销对象按钮 Button(注销对象) .onClick(() { try { this.controller.deleteJavaScriptRegister(nativeBridge); } catch (error) { console.error(ErrorCode: ${(error as BusinessError).code}, Message: ${(error as BusinessError).message}); } }) } .margin({ bottom: 10 }) // 4. Web 组件 Web({ src: $rawfile(index.html), controller: this.controller }) .width(100%) .layoutWeight(1) .javaScriptAccess(true) } .width(100%) .height(100%) .padding(20) } }Web (JS) 侧代码 (index.html)!DOCTYPE html html head titleDynamic Proxy Test/title /head body button onclickcallNative()调用原生方法/button p idresult/p script function callNative() { // 检查对象是否已注册 if (window.nativeBridge) { const msg window.nativeBridge.sayHello(); document.getElementById(result).innerText msg; } else { document.getElementById(result).innerText 原生对象未注册; } } /script /body /html代码要点解析动态注册时机与初始化时使用的.javaScriptProxy()不同registerJavaScriptProxy可以在任意运行时阶段调用例如在onPageEnd回调中或根据用户登录状态动态注入。强制刷新动态注入的对象不会自动同步到当前已加载的页面上下文中必须紧接着调用controller.refresh()重新加载页面注入才会真正生效。内存管理与注销当 H5 页面不再需要调用原生能力或者组件即将销毁时务必调用deleteJavaScriptRegister移除注入的对象。这能有效断开 ArkTS 对象与 WebView 之间的引用链防止内存泄漏。四、 进阶JSBridge 分层架构设计在实际的企业级 Hybrid 应用中建议不要将业务逻辑直接写在JavaScriptProxy中而是采用分层设计以提高通用性和灵活性通信层负责 ArkTS 与 JS 之间的数据传递屏蔽底层通信机制。通常将数据序列化为 JSON 字符串进行传递。通道层 (Channel)允许注册多种方法通道。JS 侧负责将 API 信息打包ArkTS 侧负责解包并分发给具体的处理方法处理完毕后再通过runJavaScript执行 JS 侧的回调函数。方法层具体的业务 API 实现如获取设备信息、拉起支付、路由跳转等。这种架构类似于小程序的底层通信规范能够极大地降低原生端与前端代码的耦合度便于后续的业务扩展与维护。1. ArkTS 侧通道层与通信层实现import web_webview from ohos.web.webview; // 1. 方法层定义具体的业务 API class DeviceService { getInfo(): string { return JSON.stringify({ model: HarmonyOS Device, osVersion: 5.0 }); } } // 2. 通道层负责解包、路由分发与回调 class ChannelManager { private deviceService: DeviceService new DeviceService(); // 处理来自 H5 的调用 call(channelType: string, objectJson: string): string { const params JSON.parse(objectJson); let result: any {}; if (channelType device.getInfo) { result this.deviceService.getInfo(); } else { result { code: -1, message: API not found }; } return JSON.stringify(result); } } // 3. 通信层注入到 Web 中的代理对象 class BridgeProxy { private channelManager: ChannelManager new ChannelManager(); // 这是唯一暴露给 JS 的通信方法 nativeMethod(channelType: string, objectJson: string): string { return this.channelManager.call(channelType, objectJson); } } Entry Component struct HybridPage { private webController: web_webview.WebviewController new web_webview.WebviewController(); private bridgeProxy: BridgeProxy new BridgeProxy(); build() { Column() { Web({ src: $rawfile(index.html), controller: this.webController }) .javaScriptProxy({ object: this.bridgeProxy, name: JSBridge, // 注入到 window 的对象名 methodList: [nativeMethod], // 通信白名单仅暴露通信层方法 controller: this.webController }) .width(100%) .height(100%) } } }2. Web (JS) 侧通道层与通信层实现!DOCTYPE html html headtitleJSBridge Layered Demo/title/head body button onclickcallNativeApi()获取设备信息/button p idresult/p script // 通道层封装打包与解包逻辑 function nativeCall(channelType, params) { const objectJson JSON.stringify(params); // 调用通信层注入的方法 const resultJson window.JSBridge window.JSBridge.nativeMethod(channelType, objectJson); return resultJson ? JSON.parse(resultJson) : null; } // 方法层业务调用 function callNativeApi() { const res nativeCall(device.getInfo, {}); document.getElementById(result).innerText JSON.stringify(res); } /script /body /html五、 安全权限管控Permission 配置在真实业务中将原生能力暴露给 H5 存在极大的安全风险。HarmonyOS 提供了细粒度的权限控制机制允许在javaScriptProxy注入时通过 JSON 字符串限制访问来源。核心逻辑权限配置分为对象级和方法级。对象级权限指定哪些 URL 可以访问该对象的所有方法方法级权限则进一步细化定义特定 URL 对特定方法的访问权。.javaScriptProxy({ object: this.nativeObj, name: native, methodList: [makePhoneCall, getUserInfo], controller: this.controller, // 安全权限配置 permission: { javascriptProxyPermission: { urlPermissionList: [ { scheme: https, host: trusted-domain.com, port: , path: } ], methodList: [ { methodName: makePhoneCall, urlPermissionList: [ { scheme: https, host: trusted-domain.com, port: , path: }, { scheme: resource, host: rawfile, port: , path: } ] } ] } } })安全建议务必严格校验event.origin或来源 URL避免动态拼接 JS 字符串防止 XSS 注入攻击。六、 高级通信通道WebMessagePort对于高频交互、大数据量传输或复杂的实时业务如 IM 聊天、实时音视频状态同步传统的runJavaScript和JavaScriptProxy可能面临性能瓶颈。此时推荐使用基于 HTML5 标准的WebMessagePort机制。核心逻辑原生侧调用createWebMessagePorts()创建一对消息端口[port1, port2]。将port2通过postMessage发送给 H5H5 接收后缓存该端口并监听onmessage事件。双方后续均通过port.postMessage()进行双向异步通信无需反复注入对象或执行 JS 脚本。// ArkTS 侧创建并分发端口 Button(创建数据通道) .onClick(() { const ports this.controller.createWebMessagePorts(); // 将 port[1] 传递给 H5 this.controller.postMessage(init_port, [ports[1]]); // 监听来自 H5 的消息 ports[0].onMessageEvent (message: webview.WebMessage) { console.info(收到H5消息: message.data); }; })七、 渲染性能优化同层渲染与组件鸿蒙化在 Hybrid 应用中如果 H5 内嵌了大量的原生交互组件如视频播放器、地图、复杂表单传统的 WebView 渲染会导致严重的性能损耗和交互割裂感。核心优化策略同层渲染利用 ArkWeb 提供的同层渲染能力将部分 H5 节点替换为原生 ArkUI 组件。原生组件直接嵌入到 WebView 的渲染树中获得与原生应用一致的滑动跟手体验和渲染效率。API 鸿蒙化针对 H5 侧强依赖的平台相关 API提供一套完整的 HarmonyOS 版本实现参考成熟的小程序框架规范确保原有前端业务逻辑无需大幅改动即可无缝运行在鸿蒙环境中。生命周期管理确保所有的 JSBridge 通信都在 H5 页面加载完成onPageEnd之后发起避免调用未定义的函数或对象导致异常。同时在页面销毁时及时注销代理对象防止内存泄漏。八、 架构分层MVVM 模式下的 Web 容器设计在大型应用中直接在 UI 组件中处理复杂的 Web 交互逻辑会导致代码臃肿且难以维护。建议引入 MVVM 模式进行分层解耦View 层UI 组件Web组件仅负责渲染和展示不包含任何业务逻辑。它通过Link或Prop接收来自 ViewModel 的状态如 URL、加载进度并通过事件回调通知 ViewModel 用户的交互如页面开始加载、加载完成。ViewModel 层状态与逻辑作为 Web 容器的核心管理者ViewModel 持有WebviewController实例并管理页面状态如加载进度、错误信息。它处理所有业务逻辑如权限校验、URL 拦截、错误重试等并更新状态以驱动 UI 变化。Model 层数据源定义 Web 容器的数据结构和配置可以来自本地配置或远程接口实现 Web 容器的动态化配置。九、 通信协议标准化的 JSBridge 设计直接使用runJavaScript和JavaScriptProxy进行通信会导致代码耦合度高难以维护。建议设计一套标准化的通信协议统一消息格式定义一套统一的 JSON 消息格式包含action操作类型、params参数、callbackId回调 ID等字段。所有 ArkTS 与 H5 的通信都遵循此格式。通道管理器Channel Manager在 ArkTS 侧实现一个通道管理器负责接收 H5 发来的消息根据action字段分发给不同的业务模块处理。处理完成后通过callbackId找到对应的回调函数并将结果返回给 H5。H5 SDK 封装在 H5 侧封装一个 JS SDK提供统一的invoke方法。H5 开发者只需调用invoke(actionName, params).then(...)SDK 内部负责消息的序列化、发送和回调管理对 ArkTS 的通信细节完全透明。十、 性能优化渲染与交互体验当 Web 页面内嵌大量原生交互组件时传统的 WebView 渲染会导致严重的性能损耗和交互割裂感。同层渲染Peer Rendering利用 ArkWeb 提供的同层渲染能力将部分 H5 节点如视频播放器、地图替换为原生 ArkUI 组件。原生组件直接嵌入到 WebView 的渲染树中获得与原生应用一致的滑动跟手体验和渲染效率。WebMessagePort 高频通信对于高频交互、大数据量传输或复杂的实时业务如 IM 聊天、实时音视频状态同步传统的runJavaScript和JavaScriptProxy可能面临性能瓶颈。此时推荐使用基于 HTML5 标准的WebMessagePort机制建立双向异步通信通道避免反复注入对象或执行 JS 脚本。预加载与缓存策略对于核心业务页面可以在应用启动时预加载 Web 容器并缓存静态资源。通过WebviewController的缓存接口配置合理的缓存策略减少网络请求提升页面加载速度。

相关新闻

AirDropPlus:打破生态壁垒,Windows与iPhone实现无线文件传输的完美方案

AirDropPlus:打破生态壁垒,Windows与iPhone实现无线文件传输的完美方案

AirDropPlus:打破生态壁垒,Windows与iPhone实现无线文件传输的完美方案 【免费下载链接】AirDropPlus Effortless file transfer and clipboard sync between Windows and iOS — powered by Python and Apple Shortcuts. 项目地址: https://gitcode.c…

2026/7/24 21:54:42 阅读更多 →
第11章 管道(Pipe)——让命令开始合作

第11章 管道(Pipe)——让命令开始合作

如果前面十章是学习"工具",那么从这一章开始,我们学习 Linux 的"思想"。很多人说:Linux 最厉害的是命令。其实不是。Linux 真正厉害的是:把很多简单命令组合起来,完成复杂任务。这一章&#xff0c…

2026/7/24 21:54:42 阅读更多 →
Betaflight配置器:让无人机飞控调参变得像玩游戏一样简单

Betaflight配置器:让无人机飞控调参变得像玩游戏一样简单

Betaflight配置器:让无人机飞控调参变得像玩游戏一样简单 【免费下载链接】betaflight-configurator Cross platform configuration and management application for the Betaflight firmware 项目地址: https://gitcode.com/gh_mirrors/be/betaflight-configurat…

2026/7/24 21:54:42 阅读更多 →

最新新闻

UCD3138数字电源控制器:DPWM与PCMC核心原理与PSFB实战配置

UCD3138数字电源控制器:DPWM与PCMC核心原理与PSFB实战配置

1. 项目概述:从模拟到数字的电源控制跃迁在电源设计领域,从模拟控制转向数字控制早已不是趋势,而是现实。作为一名在工业电源和服务器电源领域摸爬滚打了十多年的工程师,我亲眼见证了数字电源控制器如何从实验室里的“概念验证”一…

2026/7/24 22:02:45 阅读更多 →
DP83TC811R-Q1以太网PHY芯片RGMII与SMI接口配置实战指南

DP83TC811R-Q1以太网PHY芯片RGMII与SMI接口配置实战指南

1. 项目概述与核心价值在嵌入式网络设备开发中,选对一颗PHY芯片只是第一步,真正让它在你的板子上“活”起来,跑得稳,才是工程师价值的体现。我最近在几个车载网关和工业控制器的项目里,都深度使用了德州仪器的DP83TC81…

2026/7/24 22:02:45 阅读更多 →
入门高速PCB设计一

入门高速PCB设计一

文章目录一、如何判别信号是否为高速信号?二、传输线类别2.1 共轴传输线2.2 微带线2.3 带状线三、什么是特性阻抗?3.1 传输线与特性阻抗的关系3.2 特性阻抗与哪些因素有关3.3 PCB如何计算特性阻抗3.4 不控阻抗会造成什么影响3.5 特性阻抗分了哪几种类型四…

2026/7/24 22:02:45 阅读更多 →
Mac NTFS读写革命:开源工具Nigate如何颠覆你的跨平台文件传输体验

Mac NTFS读写革命:开源工具Nigate如何颠覆你的跨平台文件传输体验

Mac NTFS读写革命:开源工具Nigate如何颠覆你的跨平台文件传输体验 【免费下载链接】Free-NTFS-for-Mac Nigate: An open-source NTFS utility for Mac. It supports all Mac models (Intel and Apple Silicon), providing full read-write access, mounting, and ma…

2026/7/24 22:02:45 阅读更多 →
DLP3010 DMD芯片组:光学接口、热管理与系统可靠性设计实践

DLP3010 DMD芯片组:光学接口、热管理与系统可靠性设计实践

1. DLP3010 DMD芯片组:从微镜到系统的工程实践如果你正在设计一个微型投影仪、3D打印机的光固化单元,或者任何需要高速、高精度空间光调制的系统,那么德州仪器(TI)的DLP技术很可能在你的候选名单上。DLP3010作为一款0.…

2026/7/24 22:02:45 阅读更多 →
达梦数据库-学习-61-标准化部署

达梦数据库-学习-61-标准化部署

目录 一、环境信息 二、说点什么 三、实操步骤 1、用户组创建 2、创建逻辑卷 3、创建目录并挂载 4、开机自动挂载 5、赋予目录权限 5、自动化部署脚本下载链接 6、运行自动化部署脚本 (1)单机部署-兼容Oracle (2)主备…

2026/7/24 22:01:45 阅读更多 →

日新闻

用Highcharts 创建可拖拽三维散点立方体3D图表

用Highcharts 创建可拖拽三维散点立方体3D图表

该案例基于Highcharts scatter3d 三维散点图实现空间立方体散点可视化,核心特色:三维 X/Y/Z 三轴空间,所有散点分布在 0~10 立方体空间内;散点使用径向渐变实现立体 3D 圆球质感;支持鼠标 / 触屏拖拽画布,…

2026/7/24 0:00:29 阅读更多 →
AppCertDlls:进程创建路径上的 DLL 入口

AppCertDlls:进程创建路径上的 DLL 入口

AppCertDlls:进程创建路径上的 DLL 入口 AppCertDlls 位于 HKLM\System\CurrentControlSet\Control\Session Manager\AppCertDlls。本文的程序功能是只读列出这个键在 64 位和 32 位注册表视图中的全部值,并显示每条值的来源、名称、类型和可安全显示的数…

2026/7/24 0:00:29 阅读更多 →
我的编程之路:第一篇博客

我的编程之路:第一篇博客

大家好,我是一名编程初学者,同时这也是我编程学习之路上的第一篇博客。在这里,我想要向大家介绍我的一些想法和规划。a.自我介绍我是一个刚刚接触编程的新手,目前在学习c语言,我对编程世界充满了强烈的好奇。当然&…

2026/7/24 0:00:29 阅读更多 →

周新闻

Go语言静态资源打包方案对比与实践指南

Go语言静态资源打包方案对比与实践指南

1. 项目背景与核心需求在Go语言开发中,我们经常需要处理静态资源文件的打包问题。无论是Web应用的模板文件、前端资源,还是配置文件、证书等,都需要随程序一起分发。传统做法是将这些文件与编译后的二进制文件放在同一目录下,但这…

2026/7/24 3:59:20 阅读更多 →
Go语言实现高性能LDAP认证服务的架构与实践

Go语言实现高性能LDAP认证服务的架构与实践

1. 项目背景与核心价值LDAP(轻量级目录访问协议)作为企业级身份认证的黄金标准,已经服务了超过80%的财富500强公司。我在金融科技领域实施统一认证体系时,发现传统Java方案存在启动慢、内存占用高等痛点。而Go语言凭借其协程并发模…

2026/7/24 1:23:39 阅读更多 →
【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

更多请点击: https://intelliparadigm.com 第一章:AI面试官实战指南的核心价值与适用场景 AI面试官并非替代人类HR的“黑箱工具”,而是以可解释、可审计、可迭代的方式,赋能招聘全链路的关键基础设施。其核心价值在于将主观经验沉…

2026/7/24 18:52:18 阅读更多 →

月新闻