React-native使用Webview內嵌H5頁面交互

需求背景

在移動端開發中,有的業務頁面使用原生平臺開發十分繁瑣,而使用H5頁面來實現則十分便捷和高效,這就是APP+H5混合開發。

在衆多APP當中也能看到H5混合開發的頁面。這個需求是十分常見的。

 

交互機制

react-native可以使用Webview組件來內嵌H5頁面,在開發過程中,H5頁面常常要和APP端進行數據交互。

那麼這個交互機制是怎麼樣的呢?原理如下:

 

- APP端注入JS腳本到H5端,供H5頁面調用。

- H5頁面調用APP注入的JS腳本的方法,傳遞事件和數據到APP端。

- APP端在Webview組件註冊onMessage回調事件,處理H5傳遞的事件和數據。

 

這個過程主要通過Webview組件的onMessage()方法和window.ReactNativeWebView.postMessage()方法來實現的。

 

- onMessage()方法詳解:https://reactnative.cn/docs/webview#onmessage

 

Demo截圖

- 藍色按鈕,是APP端的按鈕,點擊就可以傳遞事件和數據到H5頁面。

- 藍色按鈕下方則是H5頁面,裏邊有個按鈕,點擊該按鈕,則可以傳遞事件和數據到APP端。

- 這個就是React-native使用Webview內嵌H5頁面交互過程。

 

關鍵代碼

1. APP端注入JS腳本到H5端,供H5頁面調用。注意postMessage()方法的參數要轉爲JSON字符串。

const H5AppBridge = `
    window.H5AppBridge={
        sayHello:function(data){
            let objData = {};
            // 聲明事件類型。
            objData.type='sayHello';
            objData.data = data;
            // 這裏注意要把data轉化爲JSON字符串,postMessage()只接受字符串參數。
            window.ReactNativeWebView.postMessage(JSON.stringify(objData));
        }
    };   
    true;
`;

2. APP端傳遞事件和數據到H5頁面。注意H5方法的參數要轉爲JSON字符串。

const webView = this.refs['webview_ref'];
let params = {
    msg: '這是從RN端傳來的消息'
};
// 注意:APP端傳遞參數到H5頁面,要將對象轉爲JSON字符串
let jsCode = `window.sayHello && window.sayHello(${JSON.stringify(params)});`;
// 調用H5端的方法,並傳遞數據
webView.injectJavaScript(jsCode);

3. H5頁面與APP端交互的JS代碼。

<script>
    
    function sayHelloToApp(){
        let data = {};
        data.params={
            msg:'從H5頁面發來的消息',
        };
        // 傳遞事件和數據到APP端
        window.H5AppBridge.sayHello && window.H5AppBridge.sayHello(data);
    }
             
    // 這裏的方法是提供給APP端調用的
    window.sayHello=function(data){
        alert(JSON.stringify(data));        
    }     
  
</script>

 

Demo完整代碼

import React, {Component} from 'react';
import {View, SafeAreaView, TouchableOpacity, Text} from 'react-native';
import {WebView} from 'react-native-webview';


const html = `
      <html>
      <head></head>
      <style>
      
      </style>
      <body>
      
        <h1>這是H5頁面</h1>
        <button οnclick="sayHelloToApp()">sayHelloToApp</button>
      
        <script>
            
            function sayHelloToApp(){
                let data = {};
                data.params={
                    msg:'從H5頁面發來的消息',
                };
                // 傳遞事件和數據到APP端
                window.H5AppBridge.sayHello && window.H5AppBridge.sayHello(data);
            }
                     
            // 這裏的方法是提供給APP端調用的
            window.sayHello=function(data){
                alert(JSON.stringify(data));        
            }     
          
        </script>
      </body>
      </html>
    `;

/**
 * APP端注入JS腳本到H5端,供H5頁面調用。
 * @type {string}
 */
const H5AppBridge = `
    window.H5AppBridge={
        sayHello:function(data){
            let objData = {};
            // 聲明事件類型。
            objData.type='sayHello';
            objData.data = data;
            // 這裏注意要把data轉化爲JSON字符串,postMessage()只接受字符串參數。
            window.ReactNativeWebView.postMessage(JSON.stringify(objData));
        }
    };   
    true;
`;

export default class WebviewH5 extends Component {

    constructor(props) {
        super(props);
    }

    render() {

        return (
            <SafeAreaView style={{flex: 1, paddingTop: 50,}}>

                <TouchableOpacity
                    style={{
                        height: 40,
                        borderRadius: 20,
                        paddingLeft: 15,
                        paddingRight: 15,
                        justifyContent: 'center',
                        alignItems: 'center',
                        backgroundColor: '#2988ff'
                    }}
                    onPress={() => {
                        const webView = this.refs['webview_ref'];
                        let params = {
                            msg: '這是從RN端傳來的消息'
                        };
                        // 注意:APP端傳遞參數到H5頁面,要將對象轉爲JSON字符串
                        let jsCode = `window.sayHello && window.sayHello(${JSON.stringify(params)});`;
                        // 調用H5端的方法,並傳遞數據
                        webView.injectJavaScript(jsCode);
                    }}
                >
                    <Text>
                        sayHello
                    </Text>
                </TouchableOpacity>

                <WebView
                    ref={'webview_ref'}
                    source={{html: html}}
                    // 初始化webview注入全局代碼
                    injectedJavaScript={H5AppBridge}
                    domStorageEnabled={true}
                    scrollEnabled={true}
                    javaScriptEnabled={true}
                    showsVerticalScrollIndicator={false}
                    showsHorizontalScrollIndicator={false}
                    onMessage={event => {
                        this._handleMessage(event);
                    }}
                />
            </SafeAreaView>
        );
    }

    /**
     *
     * @param event
     * @private
     */
    _handleMessage = (event) => {
        console.log("event.nativeEvent", event.nativeEvent);
        const message = event.nativeEvent;
        const webView = this.refs['webview_ref'];
        try {
            let objData = JSON.parse(message.data);
            // let data = JSON.parse(objData.data);
            let data = objData.data;
            console.log("data", data);
            switch (objData.type) {
                case 'sayHello':
                    let params = data.params;
                    if (params) {
                        alert("sayHello:" + params.msg);
                    }
                    break;
            }
        } catch (e) {
            alert("調用APP方法參數錯誤!參數爲:" + message.data);
        }
    };

}

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章