鸿蒙端Web 与原生交互方式总结

iOS端交互方式


一、原生 → H5

1. runJavaScript

原生侧主动执行任意 JS 脚本,是最直接的原生调用 H5 方式。

webController.runJavaScript("functionName('params')");
webController.runJavaScript("document.title"); // 也能获取返回值(Promise)

2. javaScriptOnDocumentStart

在 HTML 文档解析之前注入 JS 脚本,适用于注入全局变量、polyfill、监控脚本等。

Web({ src: $url, controller: webController })
  .javaScriptOnDocumentStart('window.NATIVE_ENV = "harmonyos";')

二、H5 → 原生

3. javaScriptProxy(对象注册)

原生注册一个对象暴露给 H5 调用,是 H5 调用原生最主流、最可靠 的方式。

// 原生侧
class JSBridge {
  callNative(funcId: string, data: string): string {
    // 处理 H5 调用
    return "result";
  }
}
let bridge = new JSBridge();

Web({ src: $url, controller: webController })
  .javaScriptProxy({
    object: bridge,
    name: "nativeBridge",        // H5 侧通过 window.nativeBridge 访问
    methodList: ["callNative"],  // 方法白名单
    controller: webController
  })

H5 侧调用:

window.nativeBridge.callNative("func", JSON.stringify({a: 1}));

还有两种等价写法:

  • registerJavaScriptProxy(object, name, methodList) — 通过 controller 动态注册/注销
  • deleteJavaScriptRegister(name) — 注销代理

4. onLoadIntercept(URL 拦截)

H5 通过 window.location.href 跳转特定协议,原生侧拦截解析。

Web({ src: $url, controller: webController })
  .onLoadIntercept((event: OnLoadInterceptEvent) => {
    let url = event.data.getRequestUrl();
    if (url.startsWith("myapp://")) {
      // 解析协议,处理原生逻辑
      return true; // 拦截,不加载
    }
    return false;
  })

H5 侧:

window.location.href = "myapp://action?data=xxx";
// 或
document.location = "myapp://action?data=xxx";

5. onInterceptRequest(资源请求拦截)

比 onLoadIntercept 更底层,可拦截所有资源请求(Ajax、图片等),可自定义返回内容。

Web({ src: $url, controller: webController })
  .onInterceptRequest((event: OnInterceptRequestEvent) => {
    let request = event.request;
    if (request.getRequestUrl().includes("custom-api://")) {
      // 返回自定义响应,实现伪协议通信
      event.setResponse(new WebResourceResponse(...));
    }
    return event.getResponse();
  })

6. onAlert / onConfirm / onPrompt

H5 调用 alert() / confirm() / prompt() 时原生侧可捕获,常用于轻量级数据传递。

Web({ src: $url, controller: webController })
  .onAlert((event: OnAlertEvent) => {
    let message = event.message; // H5 传入的数据
    // 处理逻辑
    event.result?.handleConfirm(); // 关闭弹窗
    return true; // 已处理,不显示系统默认弹窗
  })

H5 侧:

alert(JSON.stringify({action: "share", data: {...}}));

7. onConsole

H5 的 console.log/warn/error/debug/info 会被原生侧的 onConsole 捕获,适合调试日志收集。

Web({ src: $url, controller: webController })
  .onConsole((event: OnConsoleEvent) => {
    let logMsg = event.message.getMessage();
    let level = event.message.getLogLevel();
    // 原生日志系统记录
    return true;
  })

三、双向 / 混合

8. 消息端口(MessagePort)

通过 postMessage 机制实现双向通信,类似 Chrome 扩展的消息通道。

// 原生侧
let ports: MessagePort[] = [];
// 创建消息通道
webController.createWebMessagePorts(ports);
webController.postMessage("msgKey", [ports[0]], "*");

ports[0].onMessageEvent((result: WebMessage) => {
  // 收到 H5 消息
  let data = result.getData();
});

通信机制

原生侧 H5 侧
① createWebMessagePorts()
② postMessage 将 port 发送给 H5 ──────→ ③ window.onmessage 收到 port
④ port.onMessageEvent 监听 ←── ⑤ port.postMessage("data") 发送
⑥ port.postMessage("reply") ────────→ ⑦ port.onmessage 收到回复

原生侧(ArkTS):

@Component
struct WebPostMessageDemo {
  controller: WebviewController = new webview.WebviewController();
  ports: MessagePort[] = [];

  aboutToAppear() {
    // ① 创建消息端口
    this.ports = this.controller.createWebMessagePorts();
    
    // ④ 监听 H5 发来的消息
    this.ports[0].onMessageEvent((result: WebMessage) => {
      let data = result.getData();       // 接收到的数据
      console.log('收到 H5 消息:', data);

      // ⑥ 回复消息给 H5
      this.ports[0].postMessageEvent(
        JSON.stringify({ type: 'reply', msg: '原生已收到' })
      );
    });
  }

  build() {
    Web({ src: "https://example.com", controller: this.controller })
      .onPageEnd(() => {
        // ② 页面加载完成后,将 port 发送给 H5——这个port 自带一个单独的槽位
        // 或者通过在页面上onmessage发送到H5端(这边是原生这边通过这种方式发送)
        this.controller.postMessage('init_port', [this.ports[0]], '*');
      })
  }
}

H5 侧(JavaScript):

// ③ 接收原生发来的端口
window.addEventListener('message', (event) => {
  if (event.data === 'init_port' && event.ports.length > 0) {
    let nativePort = event.ports[0];  // 获得通信端口

    // ⑦ 监听原生回复
    nativePort.onmessage = (e) => {
      console.log('收到原生回复:', e.data);
    };

    // ⑤ 发送消息给原生
    nativePort.postMessage(JSON.stringify({
      action: 'getUserInfo',
      params: { userId: 123 }
    }));
  }
});

与 javaScriptProxy 的对比

特性 MessagePort javaScriptProxy
通信方向 双向 H5→原生为主
异步/同步 异步 同步返回
数据类型 字符串 方法参数(序列化)
多通道 支持多个 port 单一代理对象
性能 高,适合高频 一般
使用复杂度 较复杂 简单
适用场景 高频双向通信 H5 调原生能力

关键 API 说明

API 所在侧 作用
createWebMessagePorts() 原生 创建端口数组
postMessage(name, ports, uri) 原生 将端口发送到 H5 的 window.onmessage
port.onMessageEvent(callback) 原生 监听 H5 发来的消息
port.postMessageEvent(data) 原生 向 H5 发送消息
port.close() 原生 关闭端口
window.onmessage H5 接收原生发来的端口
port.postMessage(data) H5 向原生发送消息
port.onmessage H5 监听原生发来的消息

9. 生命周期事件

通过 Web 组件的事件回调感知 H5 页面状态:

事件 说明
onPageBegin 页面开始加载
onPageEnd 页面加载完成
onErrorReceive 加载出错
onTitleReceive 标题变化
onScroll 页面滚动
onRenderExited 渲染进程退出
onDownloadStart 下载开始

总结对比

方式 方向 可靠性 适用场景
javaScriptProxy H5→原生 ★★★★★ H5调用原生能力(推荐首选)
runJavaScript 原生→H5 ★★★★★ 原生通知/调用H5(推荐首选)
javaScriptOnDocumentStart 原生→H5 ★★★★ 初始化注入
onLoadIntercept H5→原生 ★★★★ URL Scheme跳转拦截
onInterceptRequest H5→原生 ★★★★ 自定义资源/伪协议
onAlert/Confirm/Prompt H5→原生 ★★★ 轻量数据传递(有性能开销)
onConsole H5→原生 ★★★ 日志收集
MessagePort 双向 ★★★★★ 高频双向消息通道

最佳实践

主力使用 javaScriptProxy + runJavaScript,复杂双向场景配合 MessagePort,辅助使用 URL 拦截处理特殊协议路由。



Web 前端视角:与原生(App)交互方式


一、Android(WebView)

H5 调用方式 说明
window.NativeObject.method() 原生注入的 JS 对象,直接调用其方法
window.location.href = "scheme://..." URL Scheme 跳转拦截
prompt("data") / alert("data") 弹窗拦截,不推荐
H5 被调方式 说明
原定注入到页面中的变量/函数 原生通过 evaluateJavascript 或 loadUrl("javascript:...") 调用 H5 函数

二、iOS(WKWebView)

H5 调用方式 说明
window.webkit.messageHandlers.xxx.postMessage(data) 向原生注册的 handler 发送消息
window.location.href = "scheme://..." URL Scheme 拦截
prompt("data") / alert("data") 弹窗拦截,不推荐
H5 被调方式 说明
页面中暴露的函数 原生通过 evaluateJavaScript 调用
注入到全局变量/函数 原生通过 WKUserScript 预注入
H5 发起请求 说明
fetch("customscheme://...") 自定义协议请求,原生通过 WKURLSchemeHandler 拦截

三、ArkWeb(鸿蒙)

H5 调用方式 说明
window.bridgeName.method() 原生通过 javaScriptProxy 注入的对象,H5 直接调用
window.location.href = "scheme://..." URL Scheme 拦截
prompt("data") / alert("data") 弹窗拦截,不推荐
H5 被调方式 说明
页面中暴露的函数 原生通过 runJavaScript 调用
注入到全局变量/函数 原生通过 javaScriptOnDocumentStart 预注入
window.onmessage 接收 MessagePort 原生通过 postMessage 发送端口,建立双向通道

四、跨平台通用总结

从 H5 角度看,无论哪个平台,本质就是这几招:

方式 平台差异
全局对象直接调 Android: window.xxx / iOS: messageHandlers.xxx / 鸿蒙: window.xxx
URL Scheme 跳转 三平台通用
弹窗拦截 三平台通用(不推荐)
被原生调 暴露函数即可,三平台通用
MessagePort 双向 鸿蒙独有

核心就一句话:H5 不管平台细节,封装一个统一 JSBridge 层,底层适配不同平台的调用方式即可。

最后编辑于 :
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容