7-5.【WebView】你说 HarmonyOS WebView 如何实现 JS 与 ArkTS 通信?是否存在跨线程调用?调用是否同步?

4 阅读3分钟

在 HarmonyOS 的 Stage 模型下,Web 组件的通信机制是构建混合开发(Hybrid)应用的核心。其底层依托于 Chromium 的 IPC(进程间通信) 机制,实现了 ArkTS(应用进程)与 JavaScript(渲染进程)的双向对话。


1. JS 与 ArkTS 通信的两种主流方式

A. ArkTS 调用 JS:runJavaScript

这是由原生侧主动发起的指令,类似于在浏览器控制台直接执行代码。

  • 原理:将字符串形式的 JS 代码发送到渲染进程的 V8 引擎中执行。

  • 示例

    TypeScript

    this.controller.runJavaScript('changeColor("blue")')
      .then(result => { /* 接收 JS 函数的返回值 */ });
    

B. JS 调用 ArkTS:registerJavaScriptProxy (推荐)

这是最常用的“桥接”方式。你可以在 ArkTS 中对象注册到 Web 组件中,JS 侧就像调用本地对象一样调用它。

  • 步骤

    1. 在 ArkTS 定义一个类(成员函数需使用 @Concurrent 或普通函数)。
    2. 使用 registerJavaScriptProxy 注册。
    3. JS 侧通过 window.objName.method() 调用。

2. 是否存在跨线程调用?

结论:不仅跨线程,而且跨进程。

这是理解性能瓶颈的关键:

  1. 进程间通信 (IPC) :ArkTS 运行在 应用主进程,而 JS 运行在 独立渲染进程。所有的通信必须经过内核的序列化和反序列化。

  2. 线程切换

    • 发送端:应用 UI 线程发起请求。
    • 中转端:系统 I/O 线程进行 IPC 传输。
    • 接收端:渲染进程的 Render Main 线程执行 JS。

3. 调用是否同步?

结论:默认是异步的,但存在特定的同步场景。

A. 异步调用(主流)

  • runJavaScript:它是非阻塞的,返回一个 Promise。原生线程发送完指令后会继续执行后续代码,不会等待 JS 执行完毕。
  • registerJavaScriptProxy:JS 调用原生方法时,默认也是异步分发的,避免 H5 侧因为等待原生返回而假死。

B. 同步调用(慎用)

  • runJavaScriptSync (API 10+) :HarmonyOS 提供了同步版本的接口,调用后原生线程会挂起等待 JS 返回结果。

    • 风险:如果 JS 侧逻辑很重,或者存在死循环,会导致应用的 UI 线程直接卡死(ANR)
  • JS 侧的同步感知:在 JS 侧调用原生代理方法时,虽然底层是 IPC,但 JS 引擎通常会表现为同步等待结果返回。


4. 性能优化与避坑指南

维度表现与影响优化方案
序列化开销传递超大 JSON 字符串会导致明显的延迟。尽量传递轻量化指令,大数据通过文件共享或 Base64 优化。
调用频率每秒数百次的 Bridge 调用会撑爆 IPC 通道。合并多次调用,采用“批处理”模式。
线程阻塞在 Bridge 的 ArkTS 回调里做耗时计算。在回调里立刻开启 TaskPool 任务,计算完再回传。

总结

  • 方式runJavaScript (下行) / registerJavaScriptProxy (上行)。
  • 本质:跨进程异步通信。
  • 规则:除非万不得已,永远不要在 UI 线程使用同步等待接口。