React Native中WebView与html双向通信遇到的坑
流星雨在线 人气:0安卓、ios原生与html双向通信相对简单且成熟,但是React Native与html的双向通信存在那么一丢丢的坑
一、参数配置
导包
import {<!--{cke_protected}{C}%3C!%2D%2D%20%2D%2D%3E--> WebView } from 'react-native-webview'
使用
<WebView ref={ref => this.webViewRef = ref} source={{ uri: url }} // source={{ html }} javaScriptEnabled useWebKit allowFileAccess startInLoadingState onLoadStart={this.onLoadStart} onError={this.onError} onLoad={this.onLoad} onLoadEnd={this.onLoadEnd} renderLoading={this.renderLoading} renderError={this.renderError} javaScriptCanOpenWindowsAutomatically onMessage={this.handleMessage} injectedJavaScript={`(function() {window.postMessage = function(data) {window.ReactNativeWebView.postMessage(data)}})();`}
相关回调函数
onLoadStart = ({ nativeEvent }) => { console.log('onLoadStart', nativeEvent) } onError = ({ nativeEvent }) => { console.log('onError', nativeEvent) } onLoad = ({ nativeEvent }) => { this.setState({ title: nativeEvent.title }) console.log('onLoad', nativeEvent) } onLoadEnd = ({ nativeEvent }) => { console.log('onLoadEnd', nativeEvent) } renderLoading = () => { console.log('renderLoading') } renderError = ({ nativeEvent }) => { console.log('renderError', nativeEvent) } handleMessage = async ({ nativeEvent }) => { const { actionType, extra } = nativeEvent.data && JSON.parse(nativeEvent.data) || {} }
二、坑点
react-native-webview使用postMessage后H5不能监听问题
注意:这里安卓用document,ios用window,否则会出现react-native-webview使用postMessage后H5不能监听问题
/* 监听rn消息 */ const eventListener = nativeEvent => { //解析数据actionType、extra const {actionType, extra} = nativeEvent.data && JSON.parse(nativeEvent.data) || {} } //安卓用document,ios用window window.addEventListener('message', eventListener); document.addEventListener('message', eventListener);
RN的webview的onMessage监听不到的问题
injectedJavaScript={<!--{cke_protected}{C}%3C!%2D%2D%20%2D%2D%3E-->`(function() {window.postMessage = function(data) {window.ReactNativeWebView.postMessage(data)}})();`}
注意这里要加上injectedJavaScript,它重写window.postMessage方法解决了RN的webview的onMessage监听不到的问题
三、React Native与html双向通信
3.1、RN发数据到WebView
RN通过postMessage发送数据
const temp = { actionType: 'takePhoto', extra: { fileId: '1522501682737836034', fileUrl: 'https://img.qb5200.com/download-x/zhongzhuanl9/jb/20230203/tt2p43f1ukk.jpg', originalFileName: 'E91FDC71-FD9C-49B9-B038-529C9CDC149B.jpg', tag: 'not_use', unionId: 'f143153ed07a428fa6308d6f73b1a2b9', }, } this.webViewRef.postMessage(JSON.stringify(temp))
webView接受数据
/* 监听rn消息 */ const eventListener = nativeEvent => { const {actionType, extra} = nativeEvent.data && JSON.parse(nativeEvent.data) || {} } //安卓用document,ios用window window.addEventListener('message', eventListener); document.addEventListener('message', eventListener);
3.2、WebView发数据到RN
WebView通过postMessage发送数据
const action = { actionType: 'viewPicture', extra: { pics: ['https://tva1.sinaimg.cn/large/e6c9d24ely1h0svk2jlcej20ps11ewld.jpg'], defaultIndex: 0, }, } window.postMessage(JSON.stringify(action));
RN注册onMessage接收
onMessage={<!--{cke_protected}{C}%3C!%2D%2D%20%2D%2D%3E-->this.handleMessage}
handleMessage = async ({ nativeEvent }) => { const { actionType, extra } = nativeEvent.data && JSON.parse(nativeEvent.data) || {} }
四、demo源码
import React, { Component } from 'react' import { DeviceEventEmitter, StyleSheet, } from 'react-native' import { WebView } from 'react-native-webview' import NavigatorBar from '../../components/NavigatorBar' import { SafeAreaView } from '../../components' export default class WebViewPage extends Component { state = { title: '', showBackAction: false, } _autoCheckNavigationBar = nativeEvent => { const { canGoBack } = nativeEvent this.setState({ showBackAction: canGoBack }) DeviceEventEmitter.emit('showTabBar', !canGoBack) } onLoadStart = ({ nativeEvent }) => { console.log('onLoadStart', nativeEvent) } onError = ({ nativeEvent }) => { console.log('onError', nativeEvent) } onLoad = ({ nativeEvent }) => { this.setState({ title: nativeEvent.title }) console.log('onLoad', nativeEvent) } onLoadEnd = ({ nativeEvent }) => { console.log('onLoadEnd', nativeEvent) this._autoCheckNavigationBar(nativeEvent) } renderLoading = () => { console.log('renderLoading') } renderError = ({ nativeEvent }) => { console.log('renderError', nativeEvent) } handleMessage = async ({ nativeEvent }) => { const { actionType, extra } = nativeEvent.data && JSON.parse(nativeEvent.data) || {} } render() { const { showBackAction } = this.state const { url } = this.props || {} return ( <SafeAreaView style={styles.container} hideBottomView={!showBackAction}> <NavigatorBar backAction={showBackAction && this.webViewRef.goBack} title={this.state.title} /> <WebView ref={ref => this.webViewRef = ref} // source={{ uri: url }} source={{ html }} javaScriptEnabled useWebKit allowFileAccess startInLoadingState onLoadStart={this.onLoadStart} onError={this.onError} onLoad={this.onLoad} onLoadEnd={this.onLoadEnd} renderLoading={this.renderLoading} renderError={this.renderError} javaScriptCanOpenWindowsAutomatically onMessage={this.handleMessage} injectedJavaScript={`(function() {window.postMessage = function(data) {window.ReactNativeWebView.postMessage(data)}})();`} /> </SafeAreaView> ) } } const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: '#F5FCFF', }, }) const html = ` <!DOCTYPE html> <html lang="en"> <head> <title>测试页面</title> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> </head> <body> <div style="text-align: center"> <button id="viewPicture">1,viewPicture</button> <p style="text-align: center">receive react native data: <span id="data"></span></p> </div> <script> window.onload = function () { /* 监听rn消息 ------------------------------------------------------------------------------------------------------------- */ const eventListener = nativeEvent => { const {actionType, extra} = nativeEvent.data && JSON.parse(nativeEvent.data) || {} } //安卓用document,ios用window window.addEventListener('message', eventListener); document.addEventListener('message', eventListener); /* 发消息给rn ------------------------------------------------------------------------------------------------------------- */ // 1、查看大图 document.getElementById('viewPicture').onclick = function () { const action = { actionType: 'viewPicture', extra: { pics: ['https://tva1.sinaimg.cn/large/e6c9d24ely1h0svk2jlcej20ps11ewld.jpg'], defaultIndex: 0, }, } window.postMessage(JSON.stringify(action)); } } </script> </body> </html> `
加载全部内容