react native 如何与 Webview 通信

1,881 阅读1分钟

目前 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"}));
};