导语:打通 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 个评论
要回复文章请先登录或注册