导语:打通 Web 与 Native 的“任督二脉”
在使用 uni-app 跨端开发时,我们经常需要在 App 内嵌一个 H5 页面(比如活动页、复杂表单页等)。
在鸿蒙(HarmonyOS)应用中,要让这个内嵌的 Web 页面和 App 的原生能力(Native)进行顺畅的沟通,就需要一个桥梁。
本文将基于 UTS 插件,在鸿蒙平台上搭建起 H5 和 App 之间的双向通信机制,实现数据的传递和方法的互调。
🎯 核心目标:实现双向通信
我们最终要实现的效果是:
- App -> H5: App 侧可以调用 H5 页面中的 JavaScript 方法,比如向 H5 传递用户 ID 或登录 Token。
 - H5 -> App: H5 页面可以调用 App 侧提供的原生方法,比如调用相册、获取地理位置,或本例中的“App 弹出提示”。
 
一、 App 侧:创建 UTS 插件并封装原生能力
在鸿蒙平台上,我们需要通过 UTS 插件来提供 App 侧供 H5 调用的原生 API。
1. 创建 UTS 插件结构
- 在 uni-app 项目的 
uni_modules目录下,新建一个 UTS 插件,命名为web-bridge-ohos。 - 确认插件目录结构如下:  
uni_modules/web-bridge-ohos/ ├── app-harmony/ │ └── index.uts ├── package.json └── interface.uts 
2. 编写 UTS 原生代码 (index.uts)
我们要实现一个核心类,这个类将作为 H5 和 App 通信的桥梁。在鸿蒙中,内嵌网页控件是 WebComponent。我们需要为它设置一个 WebMessagePort 监听器。  
在本例中,我们创建一个名为 WebInteractionModule 的类,它负责处理 H5 发送过来的消息。  
// 文件路径:uni_modules/web-bridge-ohos/app-harmony/index.uts  
import web_webview from '@ohos.web.webview';  
import hilog from '@ohos.hilog';  
import UIAbility from '@ohos.app.ability.UIAbility';  
const LOG_TAG: string = 'WebBridge';  
/**  
 * 【核心类】Web 交互模块  
 * 负责在鸿蒙平台上注入 Web 消息处理器  
 */  
export class WebInteractionModule {  
  private webViewComponent: web_webview.WebComponent | null = null;  
  /**  
   * 构造函数:初始化时可传入 WebComponent 实例  
   * @param webComp WebComponent 实例  
   */  
  constructor(webComp: web_webview.WebComponent) {  
    this.webViewComponent = webComp;  
    hilog.info(0x0001, LOG_TAG, `WebInteractionModule 初始化成功.`);  
  }  
  /**  
   * 步骤 1: 启用 H5 与 App 互通能力,设置消息监听器。  
   * @param bridgeName 桥接对象名称,H5 侧将使用此名称调用 App 方法。  
   * @param appHandler App 侧处理 H5 消息的回调函数。  
   */  
  public setupBridge(bridgeName: string, appHandler: (message: string) => void): void {  
    if (!this.webViewComponent) return;  
    // 1. 设置 Web 消息处理回调  
    this.webViewComponent.onWebMessage = (data: string) => {  
      hilog.info(0x0001, LOG_TAG, `收到 H5 消息: ${data}`);  
      // 2. 将收到的消息交给 App 业务层处理  
      appHandler(data);  
    };  
    // 3. 注入鸿蒙内置的消息通道对象(关键步骤)  
    // H5 侧将通过 window.[bridgeName].postMessage('data') 来调用  
    this.webViewComponent.injectWebMessagePort(bridgeName);  
    hilog.info(0x0001, LOG_TAG, `已注入 Web 桥接对象: ${bridgeName}`);  
  }  
  /**  
   * 步骤 2: 从 App 侧调用 H5 页面内的 JavaScript 方法。  
   * @param jsCode 要执行的 JavaScript 代码(如:`window.myH5Method('Hello from App')`)。  
   */  
  public callH5Function(jsCode: string): void {  
    if (this.webViewComponent) {  
      this.webViewComponent.executeJs(jsCode, (result) => {  
        hilog.info(0x0001, LOG_TAG, `执行 H5 JS 代码结果: ${result}`);  
      });  
    }  
  }  
}  
// =======================================================  
// 为了方便 uni-app 调用,我们提供一个 UTS 导出的工厂函数  
// =======================================================  
/**  
 * 导出工厂函数:创建并返回 WebInteractionModule 实例  
 * @param webComp H5 视图的 WebComponent 实例  
 * @returns WebInteractionModule 实例  
 */  
export function createWebBridge(webComp: web_webview.WebComponent): WebInteractionModule {  
  return new WebInteractionModule(webComp);  
}
3. UTS 接口定义 (interface.uts)
为了让上层 Vue/JS 代码能顺利使用这个类,我们需要定义接口:
// 文件路径:uni_modules/web-bridge-ohos/interface.uts  
import web_webview from '@ohos.web.webview';  
/**  
 * WebInteractionModule 类的接口定义  
 * 供 uni-app TypeScript/JavaScript 代码使用  
 */  
export interface WebInteractionModule {  
  /**  
   * 启动 App 和 H5 之间的通信桥接。  
   * @param bridgeName H5 侧调用的对象名 (如:'HarmonyAppBridge')  
   * @param appHandler App 侧接收 H5 消息的回调函数。  
   */  
  setupBridge(bridgeName: string, appHandler: (message: string) => void): void;  
  /**  
   * 从 App 侧调用 H5 页面中的 JavaScript 代码。  
   * @param jsCode 要在 H5 中执行的 JS 字符串。  
   */  
  callH5Function(jsCode: string): void;  
}  
/**  
 * UTS 导出函数接口:创建 Web 桥接模块实例  
 * @param webComp WebComponent 实例  
 * @returns WebInteractionModule 实例  
 */  
export type CreateWebBridge = (webComp: web_webview.WebComponent) => WebInteractionModule;
二、 App 侧:在 uni-app 页面中集成 WebComponent
在 uni-app 页面中,我们需要使用自定义组件的方式,引入鸿蒙平台专有的 web-view 组件,并调用 UTS 插件。  
1. 页面逻辑 (pages/index/index.vue)
我们创建一个页面,其中包含一个内嵌的 web-view 组件,并实现 H5 消息处理逻辑。  
<template>  
  <view class="container">  
    <text class="title">鸿蒙 Web-Native 互通演示</text>  
    <button @click="sendDataToH5">App 发送数据给 H5</button>  
    <view class="message-box">  
      <text>收到 H5 消息: {{ lastH5Message }}</text>  
    </view>  
    <web-view   
      ref="h5WebView"   
      class="h5-content"   
      :src="h5Url"   
      @onHarmonyWebComponentCreated="onWebCreated"   
    ></web-view>  
  </view>  
</template>  
<script lang="uts">  
  import { WebInteractionModule, createWebBridge } from '@/uni_modules/web-bridge-ohos';  
  import web_webview from '@ohos.web.webview';  
  // 【注意】请替换成你实际 H5 文件的网络地址或本地路径  
  const H5_PAGE_URL: string = 'https://yourdomain.com/path/to/h5/index.html';   
  const BRIDGE_OBJECT_NAME: string = 'HarmonyAppBridge'; // 供 H5 调用的对象名  
  export default {  
    data() {  
      return {  
        h5Url: H5_PAGE_URL,  
        lastH5Message: '暂无消息',  
        webBridge: null as WebInteractionModule | null, // 存储 UTS 桥接模块实例  
        sendCount: 0,  
      }  
    },  
    methods: {  
      /**  
       * 鸿蒙平台 WebComponent 创建成功后触发的事件  
       * @param e 事件对象,包含了 WebComponent 的实例  
       */  
      onWebCreated(e: { component: web_webview.WebComponent }) {  
        console.log('WebComponent 实例已创建');  
        const webComponent = e.component;  
        // 1. 创建 UTS 桥接模块实例  
        this.webBridge = createWebBridge(webComponent);  
        // 2. 设置桥接并注册 App 侧的消息处理器  
        this.webBridge.setupBridge(BRIDGE_OBJECT_NAME, this.handleMessageFromH5);  
      },  
      /**  
       * App 侧处理 H5 页面发送过来的消息  
       * @param message H5 传递过来的 JSON 字符串  
       */  
      handleMessageFromH5(message: string): void {  
        console.log(`App 收到 H5 消息: ${message}`);  
        this.lastH5Message = message;  
        // 示例:App 收到 H5 消息后,可以调用 App 的原生能力,比如 uni.showToast  
        uni.showToast({  
          title: `H5 说: ${message}`,  
          icon: 'none',  
        });  
      },  
      /**  
       * App 侧主动调用 H5 页面中的 JavaScript 方法  
       */  
      sendDataToH5(): void {  
        if (!this.webBridge) {  
          console.error('Web 桥接尚未初始化!');  
          uni.showToast({ title: '桥接未就绪', icon: 'error' });  
          return;  
        }  
        this.sendCount++;  
        const dataToSend = `{"action":"updateUser","userId":1000${this.sendCount}}`;  
        // 构造要执行的 H5 JS 代码  
        // 假设 H5 页面中有一个全局函数名为 `receiveAppMessage`  
        const jsCode: string = `window.receiveAppMessage('${dataToSend}')`;  
        // 调用 UTS 插件方法执行 JS  
        this.webBridge.callH5Function(jsCode);  
      }  
    }  
  }  
</script>  
<style>  
  .container {  
    padding: 20px;  
  }  
  .title {  
    font-size: 18px;  
    font-weight: bold;  
    margin-bottom: 20px;  
    display: block;  
  }  
  .message-box {  
    margin: 15px 0;  
    padding: 10px;  
    border: 1px solid #ddd;  
    background-color: #f0f0f0;  
  }  
  .h5-content {  
    /* 确保 web-view 有足够的高度显示 */  
    width: 100%;  
    height: 300px;   
    margin-top: 20px;  
    border: 1px solid #ccc;  
  }  
</style>
三、 H5 侧:实现双向通信逻辑
H5 页面需要实现两套机制:一套用于接收 App 消息,一套用于发送消息给 App。
1. H5 接收 App 消息的函数
App 侧会调用我们在 H5 中定义的全局函数 window.receiveAppMessage。  
<script>  
  // 【接收】App -> H5  
  window.receiveAppMessage = function(dataStr) {  
    console.log('H5 收到 App 消息:', dataStr);  
    try {  
      const data = JSON.parse(dataStr);  
      document.getElementById('app-msg').innerText = '最新 App 消息: ' + data.action + ',用户ID:' + data.userId;  
    } catch (e) {  
      document.getElementById('app-msg').innerText = '收到非法消息格式: ' + dataStr;  
    }  
  };  
</script>
2. H5 发送消息给 App 的方法
H5 通过调用 App 侧注入的桥接对象(我们命名为 HarmonyAppBridge)上的 postMessage 方法来发送消息。  
<script>  
  // 【发送】H5 -> App  
  function sendToApp(message) {  
    // 检查 App 侧注入的桥接对象是否存在  
    if (window.HarmonyAppBridge && typeof window.HarmonyAppBridge.postMessage === 'function') {  
      window.HarmonyAppBridge.postMessage(message);  
      document.getElementById('h5-status').innerText = '成功发送消息给 App: ' + message;  
    } else {  
      document.getElementById('h5-status').innerText = 'App 桥接对象 (HarmonyAppBridge) 不存在或未就绪!';  
      console.error('App 桥接对象不存在,无法发送消息。');  
    }  
  }  
  // 按钮点击事件示例  
  document.getElementById('send-btn').onclick = function() {  
    const time = new Date().toLocaleTimeString();  
    const message = `{"event":"h5Ready","time":"${time}"}`;  
    sendToApp(message);  
  };  
</script>  
<div>  
    <h1>H5 页面内容</h1>  
    <p id="app-msg">最新 App 消息: 暂无</p>  
    <button id="send-btn">H5 调用 App 弹窗</button>  
    <p id="h5-status"></p>  
</div>
总结
通过上述三个部分的协作,我们成功地在 uni-app 鸿蒙应用中搭建了 H5 页面和 App 之间的通信桥梁:
- App 侧 (UTS): 使用 
WebInteractionModule类和WebComponent的原生能力,通过injectWebMessagePort注入发送通道,通过onWebMessage接收 H5 消息。 - App 侧 (Vue): 使用 
<web-view>组件,并通过onHarmonyWebComponentCreated事件获取WebComponent实例,将其实例传递给 UTS 插件进行初始化和监听。 - H5 侧 (JS): 通过调用全局注入的 
window.HarmonyAppBridge.postMessage()发送消息给 App,并通过全局函数window.receiveAppMessage()接收 App 的指令。 
全文完,欢迎点赞、收藏、转发!
            
            
            
            
0 个评论
要回复文章请先登录或注册