背景介绍
在混合开发中,H5 页面与原生应用的通信是一个常见需求。本文将详细介绍如何实现 H5 与 React Native WebView 之间的双向通信机制。
核心实现
首先,我们需要在 H5 端实现一个回调管理器,用于处理与原生端的通信:
1. H5 端完整实现
// 回调管理器
window.NativeCallbacks = {callbacks: {},register: function(type, successCallback, errorCallback) {const callbackId = type + Date.now().toString();// Promise方式if (!successCallback && !errorCallback) {const promise = new Promise((resolve, reject) => {this.callbacks[callbackId] = {success: resolve,error: reject,};});return {promise,callbackId};}// 回调方式this.callbacks[callbackId] = {success: successCallback, error: errorCallback,};return callbackId;},execute: function(callbackId, type, data) {const callback = this.callbacks[callbackId];if (callback) {if (type === 'success') {callback.success && callback.success(data);} else {callback.error && callback.error(data);}delete this.callbacks[callbackId]; // 执行后清理回调}}
};// 原生通信接口封装
window.Native = {// 回调方式getUserInfo: function(successCallback, errorCallback) {const callbackId = ntalkCallbacks.register('getUserInfo', successCallback, errorCallback);window.ReactNativeWebView.postMessage(JSON.stringify({type: 'getUserInfo',callbackId,data: null}));},// Promise方式getUserInfoAsync: async function() {const { promise, callbackId } = ntalkCallbacks.register('getUserInfo');window.ReactNativeWebView.postMessage(JSON.stringify({type: 'getUserInfo',callbackId,data: null}));return promise;}
};
2. React Native 端完整实现
interface MessageData {type: string;callbackId: string;data: any;
}class WebViewManager {private webview: WebView;constructor(webview: WebView) {this.webview = webview;}handleMessage(message: string) {try {const data: MessageData = JSON.parse(message);const { type, callbackId, data: payload } = data;switch(type) {case 'getUserInfo':this.handleGetUserInfo(callbackId, payload);break;case 'setAppCacheValue':this.handleSetAppCache(callbackId, payload);break;default:this.sendCallback(callbackId, 'error', '未知的消息类型');}} catch (error) {console.error('消息处理错误:', error);}}sendCallback(callbackId: string, type: 'success' | 'error', data: any) {const script = `window.ntalkCallbacks.execute('${callbackId}','${type}',${JSON.stringify(data)});`;this.webview.injectJavaScript(script);}private handleGetUserInfo(callbackId: string, payload: any) {try {// 实际项目中从本地存储或状态管理中获取const userInfo = {userId: '123',name: '张三',avatar: 'https://example.com/avatar.png'};this.sendCallback(callbackId, 'success', userInfo);} catch (error) {this.sendCallback(callbackId, 'error', error.message);}}private handleSetAppCache(callbackId: string, payload: any) {try {const { key, value } = payload;// 实际项目中进行缓存操作this.sendCallback(callbackId, 'success', true);} catch (error) {this.sendCallback(callbackId, 'error', error.message);}}
}// WebView 组件使用示例
function MyWebView() {const webViewRef = useRef<WebView>(null);const webViewManager = useRef<WebViewManager>();useEffect(() => {if (webViewRef.current) {webViewManager.current = new WebViewManager(webViewRef.current);}}, []);return (<WebViewref={webViewRef}source={{ uri: 'https://example.com' }}onMessage={(event) => {webViewManager.current?.handleMessage(event.nativeEvent.data);}}/>);
}
3. 使用示例
// 示例1:回调方式
Native.getUserInfo((userInfo) => {console.log('获取用户信息成功:', userInfo);},(error) => {console.error('获取用户信息失败:', error);}
);// 示例2:Promise方式
async function getUserData() {try {const userInfo = await ntalkNative.getUserInfoAsync();console.log('获取用户信息成功:', userInfo);} catch (error) {console.error('获取用户信息失败:', error);}
}