目录
  • 一、参数配置
  • 二、坑点
  • 三、React Native与html双向通信
    • 3.1、RN发数据到WebView
    • 3.2、WebView发数据到RN
  • 四、demo源码

    安卓、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://gongbao-phoenix.oss-cn-hangzhou.aliyuncs.com/test/330100/1/2022/05/06/2efb943b439146ed86db0ad920c7edaf.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>
    `

    声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。