NetLab 的网络拓扑画布和 CLI 终端都是用 Web 组件嵌入前端页面实现的。Web 组件让鸿蒙应用能复用成熟的前端生态,是混合开发的关键能力。本文分享 Web 组件加载、rawfile 资源访问、双向通信实战。

一、Web 组件基础

import { webview } from '@kit.ArkWeb';

@Entry
@Component
struct WebPage {
  controller: webview.WebviewController = new webview.WebviewController();

  build() {
    Web({ src: $rawfile('index.html'), controller: this.controller })
      .width('100%')
      .height('100%')
      .javaScriptAccess(true)  // 允许JS
      .domStorageAccess(true)  // 允许localStorage
  }
}

二、加载资源方式

2.1 加载本地 rawfile

// 资源放在 entry/src/main/resources/rawfile/ 下
Web({ src: $rawfile('canvas/index.html') })

// 目录结构:
// rawfile/
//   canvas/
//     index.html
//     js/topology.js
//     css/style.css

rawfile 资源打包进 HAP,无需网络,离线可用。NetLab 的拓扑画布全部放在 rawfile 下。

2.2 加载远程 URL

Web({ src: 'https://netlab.guidl.top/' })

需配置网络权限 ohos.permission.INTERNET。

2.3 沙箱协议(file:///rawfile://)

// file://protocol 访问应用沙箱文件
Web({ src: 'file://' + getContext().filesDir + '/cache.html' })

三、双向通信(核心)

3.1 ArkTS 调用前端 JS

// ArkTS 侧:通过 controller 执行 JS
this.controller.runJavaScriptCode(`
  window.loadTopology('${topologyJson}');
`);

// 前端侧:定义全局方法
window.loadTopology = function(json) {
  const topo = JSON.parse(json);
  renderTopology(topo);
};

3.2 前端 JS 调用 ArkTS(javaScriptProxy)

// ArkTS 侧:注册代理对象供前端调用
class NativeBridge {
  saveTopology(json: string) {
    // 保存到鸿蒙本地存储
    preferences.put('topology', json);
  }
  showToast(msg: string) {
    promptAction.showToast({ message: msg });
  }
}

Web({ src: $rawfile('index.html') })
  .javaScriptAccess(true)
  .registerJavaScriptProxy({
    object: new NativeBridge(),
    name: 'nativeBridge',  // 前端通过 window.nativeBridge 调用
    methodList: ['saveTopology', 'showToast'],
    asyncMethodList: [],
    isAsync: false
  })

// 前端侧:调用原生方法
document.getElementById('save').onclick = () => {
  const json = JSON.stringify(getTopology());
  window.nativeBridge.saveTopology(json);
  window.nativeBridge.showToast('已保存');
};
💡
通信模式:ArkTS→JS 用 runJavaScriptCode 执行前端方法;JS→ArkTS 用 registerJavaScriptProxy 注册代理对象。双向配合实现混合架构交互。

四、NetLab 实战案例

NetLab 拓扑画布的完整交互链路:

用户拖拽设备(前端事件)
  → 前端更新画布渲染
  → window.nativeBridge.onTopologyChange(json)  // 通知原生
  → ArkTS 保存拓扑到本地存储
  → 触发撤销栈记录

用户点击"加载实验"(ArkTS按钮)
  → controller.runJavaScriptCode('loadExperiment(...)')  // 调前端
  → 前端解析JSON渲染拓扑
  → window.nativeBridge.onLoadComplete()  // 回调原生
  → ArkTS 更新UI状态

五、踩坑经验

  1. rawfile 路径:用 $rawfile('path'),不能用字符串拼接到 rawfile 绝对路径
  2. 代理注册时机:registerJavaScriptProxy 需在 Web 组件 onLoadIntercept 或 onControllerAttached 中注册,太早注册无效
  3. 前端资源相对路径:rawfile 下的 HTML 引用 JS/CSS 用相对路径,不能用绝对路径
  4. 跨域限制:远程页面调用 registerJavaScriptProxy 受跨域策略限制,本地 rawfile 无此问题

六、小结

  • Web 组件让鸿蒙复用前端生态,适合复杂画布/终端等场景
  • rawfile 打包本地资源,离线可用,路径用 $rawfile()
  • 双向通信:runJavaScriptCode(ArkTS→JS)+ registerJavaScriptProxy(JS→ArkTS)
  • NetLab 拓扑画布 + CLI 终端均用此方案,混合架构成熟可靠