通过 useEventBus 和 useEventCallBack 实现与原生 Android、鸿蒙、iOS 的事件交互
通过 useEventBus 和 useEventCallBack 实现与 原生 Android、鸿蒙、iOS 的事件交互
这个问题在 H5 嵌入 Native 容器(如 WebView)的混合开发场景中非常常见。我们来一步步解释原理、机制和实现方式。
✅ 一、H5 与原生通信的基本原理
在 Hybrid App 中,H5 页面运行在 WebView 内部,要与原生(Android/iOS/HarmonyOS)交互,通常使用以下两种方式:
| 方式 | 说明 |
|---|---|
| JSBridge | 原生注入 JS 对象或函数到 WebView 的 window 上,H5 调用它发送消息;原生也可以主动调用 JS 函数 |
| postMessage | 更现代的方式,通过 window.postMessage 发送消息,原生监听并响应 |
你的项目中使用的 useEventBus 和 useEventCallBack 很可能是基于这两种机制封装的事件总线模式。
✅ 二、核心机制:JavaScript ↔ Native 双向通信
🔄 1. H5 → 原生(发送事件)
// 方式一:调用原生暴露的方法(JSBridge)
window.Android?.sendMessage('eventName', data);
window.webkit.messageHandlers.iOS?.postMessage({ event: 'click', data });// 方式二:通过统一 bridge(比如 JSBridge)
window.JSBridge?.call('openCamera', { quality: 'high' });
🔄 2. 原生 → H5(触发事件)
原生通过执行 JS 代码调用 H5 注册的回调函数:
// 原生执行:
window.dispatchEvent(new CustomEvent('native_event_login_success', {detail: { token: 'xxx' }
}));
或者直接调用全局函数:
window.onNativeLoginSuccess && window.onNativeLoginSuccess(res);
✅ 三、结合你的代码分析
import useEventBus from '@/hooks/useEventBus';
import { NATIVE_EVENT, useEventCallBack } from './hooks/useEventCallBack';
我们可以推测这两个 Hook 的作用是:
| Hook | 功能 |
|---|---|
useEventCallBack | 监听来自原生的事件(如登录成功、返回键点击等) |
useEventBus | 主动向原生发送事件(如打开相机、跳转页面) |
✅ 四、具体实现示例
✅ 1. 定义原生事件常量
// constants.ts
export const NATIVE_EVENT = {LOGIN_SUCCESS: 'login_success',PAY_RESULT: 'pay_result',BACK_BUTTON: 'back_button',NETWORK_CHANGE: 'network_change',
} as const;
✅ 2. useEventCallBack:监听原生事件
// hooks/useEventCallBack.ts
import { useEffect } from 'react';// 模拟原生事件映射表
const nativeEventListeners: Record<string, (data: any) => void> = {};// 暴露给原生调用的全局方法
(window as any).onNativeEvent = (event: string, data: string) => {const listener = nativeEventListeners[event];if (listener) {listener(JSON.parse(data));}
};export function useEventCallBack(event: string, callback: (data: any) => void) {useEffect(() => {nativeEventListeners[event] = callback;// 清理return () => {delete nativeEventListeners[event];};}, [event, callback]);
}export { NATIVE_EVENT };
原生代码需要知道这个入口:
window.onNativeEvent("login_success", "{\"token\":\"abc\"}")
✅ 3. useEventBus:向原生发送事件
// hooks/useEventBus.ts
export default function useEventBus() {const sendToNative = (event: string, data?: any) => {const message = { event, data };// 【Android & HarmonyOS】if (window.AndroidBridge) {window.AndroidBridge.sendMessage(JSON.stringify(message));}// 【iOS】WKWebView postMessageelse if (window.webkit?.messageHandlers?.NativeHandler) {window.webkit.messageHandlers.NativeHandler.postMessage(message);}// 【HarmonyOS ArkWeb】可能有自己的 bridgeelse if ((window as any).ArkJSBridge) {(window as any).ArkJSBridge.call(JSON.stringify(message));}// 开发环境模拟else {console.warn('[Mock] Send to Native:', message);}};return { sendToNative };
}
✅ 五、实际使用案例
示例 1:H5 请求原生打开相机
function CameraButton() {const { sendToNative } = useEventBus();const handleClick = () => {sendToNative('open_camera', { resolution: 'high' });};return <button onClick={handleClick}>打开相机</button>;
}
示例 2:监听原生返回键事件
function BackListener() {useEventCallBack(NATIVE_EVENT.BACK_BUTTON, (data) => {console.log('用户点击了返回键', data);// 执行某些逻辑,比如退出当前页});return null; // 不渲染 UI
}
示例 3:监听登录成功事件
function AuthListener() {useEventCallBack(NATIVE_EVENT.LOGIN_SUCCESS, (data) => {console.log('原生登录成功:', data.token);// 存储 token,更新状态commonStore.setToken(data.token);});return null;
}
✅ 六、原生端配合示例(伪代码)
Android / HarmonyOS(Java/Kotlin/ArkTS)
// Android WebView
webView.evaluateJavascript("onNativeEvent('login_success', '{\"token\":\"abc123\"}')",null
);
iOS(Swift)
webView?.evaluateJavaScript("onNativeEvent('pay_result', '{\"status\":\"success\"}')")
✅ 七、兼容性建议
| 平台 | 推荐通信方式 |
|---|---|
| Android | addJavascriptInterface 或自定义 JSBridge |
| iOS (WKWebView) | webkit.messageHandlers |
| HarmonyOS | ArkWeb 支持 @Concurrent + JSBridge |
| 调试阶段 | 使用 vConsole 打印日志 |
✅ 总结
| 目标 | 实现方式 |
|---|---|
| H5 → 原生 | useEventBus().sendToNative() 调用原生方法 |
| 原生 → H5 | 原生执行 JS 触发 onNativeEvent(eventName, data) |
| 统一事件管理 | 使用 NATIVE_EVENT 枚举定义事件名 |
| 防止耦合 | 封装成 Hook,便于复用和测试 |
