Appearance
没问题~一句话概括:ArkTS ↔ HTML 在鸿蒙里主要有三条通道——
- ArkTS 调 JS:
WebviewController.runJavaScript / runJavaScriptExt - JS 调 ArkTS:
javaScriptProxy / registerJavaScriptProxy注入原生对象 - 双向消息通道:
createWebMessagePorts + postMessage(WebMessagePort)
下面把“主要 API + 最常见用法”捋清楚(含小例子)。
1) ArkTS 调用网页里的 JS
什么时候用:把 Store 里的数据推给网页、调用 window.LifeChart.setAll(...) 等。
controller.runJavaScript(script: string):异步执行一段 JS。常在onPageEnd后调用,确保网页已就绪。(华为开发者官网)controller.runJavaScriptExt(script: string):也是执行 JS,但能拿返回值(Promise 风格,返回 JsValue,可getString()/getNumber()等)。(华为开发者官网)
示例(ArkTS):
ts
// 页面加载完后注入
.onPageEnd(() => {
// 推数据
const data = [{ question: '人生', percent: 0.38 }];
this.controller.runJavaScript(
`window.LifeChart && window.LifeChart.setData(${JSON.stringify(data)})`
);
// 取网页返回值(如读取 document.title)
this.controller.runJavaScriptExt('document.title').then(result => {
const title = result.getString(); // ArkWeb JsValue
console.info('[WebTitle]', title);
});
});要点:把注入放在
onPageEnd等网页完成回调之后,避免目标函数尚未挂载。(华为开发者官网)
2) 网页调用 ArkTS(注入原生对象)
什么时候用:H5 希望直接触发原生能力(如读取设置、调用端能力等)。
- 初始化时注入:
javaScriptProxy(Web 组件属性) - 初始化完成后注入:
controller.registerJavaScriptProxy(...)
这两个都能把 ArkTS 对象“挂”到前端环境里(通常是 window.XXX),JS 直接调你暴露的方法。(华为开发者官网)
示例(ArkTS,在 onControllerAttached 里注册):
ts
this.controller.registerJavaScriptProxy({
name: "NativeBridge", // 前端可直接调用 NativeBridge.xxx()
methodList: ["hello", "update"],
object: {
hello: (): string => {
return "Hi from ArkTS";
},
update: (json: string): void => {
// 处理来自 H5 的数据
// ... 更新 Store 或执行业务
},
},
});示例(网页 JS 调用原生):
js
// H5
const msg = window.NativeBridge.hello();
window.NativeBridge.update(JSON.stringify({ age: 30 }));官方文档场景叫“前端页面调用应用侧函数”,支持
javaScriptProxy与registerJavaScriptProxy()两种注入时机。(OpenHarmony)
3) 双向消息通道(更通用/更安全)
什么时候用:需要持续、双工传递数据(如事件流、较大 JSON),且不想暴露大量同步方法。
- 建通道:
controller.createWebMessagePorts() - 发送端口到 H5:
controller.postMessage(...)(把其中一个端口发给网页) - 收消息/发消息:ArkTS 侧
WebMessagePort.onMessageEvent / postMessageEvent;H5 侧使用MessagePort的onmessage / postMessage。(cnblogs.com)
ArkTS(建立通道并把端口发给 H5):
ts
const ports = this.controller.createWebMessagePorts();
ports[1].onMessageEvent((msg) => {
const payload = msg.getString ? msg.getString() : "";
console.info("[H5->ETS]", payload);
});
// 把 ports[0] 发给网页,网页保存后即可双向通信
this.controller.postMessage("__init_port__", [ports[0]], "*");H5(接收端口并通信):
js
let h5Port = null;
window.addEventListener("message", (e) => {
if (e.data === "__init_port__" && e.ports?.[0]) {
h5Port = e.ports[0];
h5Port.onmessage = (evt) => console.log("[ETS->H5]", evt.data);
// 向 ArkTS 发消息
h5Port.postMessage(JSON.stringify({ type: "PING" }));
}
});该方案基于 WebMessagePort,自 API9 起提供,适合做持久双工通道;官方也推荐用消息通道替代过度的对象注入以提升安全性。(cnblogs.com)
4) 其它有用回调
onPageBegin / onPageEnd / onProgressChange:注入时机与进度控制。(CSDN 博主)onConsole / onAlert / onConfirm / onPrompt:接管网页日志与弹框(便于调试与原生 UI 替换)。(华为开发者官网)
5) 选型建议(实践经验)
- 推数据到 H5:优先
runJavaScript*,简单直接(我们前面给你的 G2 图表就是这样做)。(Medium) - H5 触发原生能力:少量方法用
registerJavaScriptProxy;多而频的交互更建议 消息通道。(华为开发者官网) - 时机:所有注入/调用尽量放在
onPageEnd之后。(华为开发者官网)
如果你要,我可以把这三种方式的最小模板直接嵌到你现有的 LifeChart 组件和 index.html 里,按你现在的项目结构一键跑通。