目前 react native 已经不自带 Webview 组件了,官网也推荐使用社区包 react-native-community/react-native-webview 替代,单纯地做信息展示等是比较简单的,但嵌入 APP 内的网页通常会有相互通信的需求,下面介绍下 RN 端和 Web 端如何相互通信
RN 端发送信息给 Web 端
-
带查询参数的 Url
我做过一个 app,它的商城页面是 web 做的,因为部分用户有在浏览器下单的习惯。在 app 里,如果是登录的状态,用户进入商城也是登录的状态,这是怎么做到的呢?app 跳转到商城前,会检查登录状态,如果已登录的话,会把 token 等参数拼到 url 上,商城 web 端在去解析参数完成自动登录
-
使用 webview 实例的 postMessage
创建一个 webView 实例,调用它的 postMessage 方法,当然还是只能传输字符串,格式还是两端约定好
const Demo = () => { const webviewRef = useRef<WebView | null>(null); return ( <WebView source={{ uri }} ref={(instance) => { webviewRef.current = instance; }} onLoadEnd={() => { webViewRef.current?.postMessage('RN Message'); }} /> ); };web 端如何接收呢,监听 message 事件
const receiveMessage = (event) => { const msg = event?.data; // handle msg }; document.addEventListener("message", receiveMessage); window.addEventListener("message", receiveMessage);
Web 端发送信息给 RN 端
RN 接收信息通过是通过 Webview 组件的 onMessage 接口,当然,你可能需要覆盖 Web 端原生的 postMessage 方法
const Demo = () => {
const injectedJavaScript = `
(function() {
window.postMessage = function(data) {
window.ReactNativeWebView.postMessage(data);
};
})()`;
return (
<WebView
source={{ uri }}
injectedJavaScript={injectedJavaScript}
onMessage={(event) => {
try {
// 传过来的 data 肯定为字符串,可以跟 web 端约定好交互的数据格式
const data = JSON.parse(event.nativeEvent.data);
} catch (error) {
// handle parse error
}
}}
/>
);
};
下图演示的 postMessage 如果是在 webview 中加载的,那它就已经被覆写了
// Web 端发送信息给 RN
const postMsgToRN = () => {
window.postMessage(JSON.stringify({code: "SUBMIT"}));
};
当然,有不用覆盖的方法,也更推荐
const postMsgToRN = () => {
window.ReactNativeWebView?.postMessage(JSON.stringify({code: "SUBMIT"}));
};