React Native WebView postMessage 不起作用

Posted

技术标签:

【中文标题】React Native WebView postMessage 不起作用【英文标题】:React Native WebView postMessage does not work 【发布时间】:2017-04-30 19:45:35 【问题描述】:

我无法让 React Native WebView postMessage 工作。 React Native 应用程序成功接收到来自 Web 应用程序的 post 消息。但是 Web 应用没有收到 React Native 应用发送的消息。

我的简单网络应用

<html>
<body>

<button>Send post message from web</button>
<div>Post message log</div>
<textarea style="height: 50%; width: 100%;" readonly></textarea>

<script>
var log = document.querySelector("textarea");

document.querySelector("button").onclick = function() 
    console.log("Send post message");

    logMessage("Sending post message from web..");
    window.postMessage("Post message from web", "*");


window.addEventListener("message", function(event) 
    console.log("Received post message", event);

    logMessage(event.data);
, false);

function logMessage(message) 
    log.append((new Date()) + " " + message + "\n");


</script>

</body>
</html>

此网络应用托管在:https://popping-heat-6062.firebaseapp.com/

我的简单 React Native 应用

import React, Component from "react";
import AppRegistry, Text, View, TouchableHighlight, WebView from "react-native";

export default class WevViewApp extends Component 

    constructor( props ) 
        super( props );

        this.webView = null;
    

    onMessage( event ) 
        console.log( "On Message", event.nativeEvent.data );
    

    sendPostMessage() 
        console.log( "Sending post message" );
        this.webView.postMessage( "Post message from react native" );
    

    render() 
        return (
            <View style=flex: 1>
                <TouchableHighlight style=padding: 10, backgroundColor: 'blue', marginTop: 20 onPress=() => this.sendPostMessage()>
                    <Text style=color: 'white'>Send post message from react native</Text>
                </TouchableHighlight>
                <WebView
                    style=flex: 1
                    source=uri: 'https://popping-heat-6062.firebaseapp.com'
                    ref=( webView ) => this.webView = webView
                    onMessage=this.onMessage
                />
            </View>
        );
    


AppRegistry.registerComponent( 'WevViewApp', () => WevViewApp );

预期结果

    单击“从网络发送帖子”按钮发送 向 React Native 应用程序发布消息并在调试器中登录 窗口 单击“从 React Native 发送帖子”按钮 向 Web 应用程序发送帖子消息并在 Web 中打印出来 文本区域

实际结果

    Web 应用成功向 React Native 应用发送消息并登录到调试器窗口 React Native 应用程序不成功向网络应用程序发送消息,并且未在网络文本区域中打印出来

有人知道为什么网络应用没有收到消息吗?

通过 androidios 测试。

相关文档:https://facebook.github.io/react-native/docs/webview.html


编辑:经历了可能查明问题的行为。

当直接在网络浏览器中测试“从网络发送帖子”按钮时,textarea 会记录它已经发送了消息并且收到了它自己的消息。

Thu Dec 15 2016 10:20:34 GMT+0100 (CET) Sending post message from web..
Thu Dec 15 2016 10:20:34 GMT+0100 (CET) Post message from web

在 React Native 应用程序的 WebView 中尝试相同操作时,textarea 只会打印出来

Thu Dec 15 2016 10:20:34 GMT+0100 (CET) Sending post message from web..

WebView 是否劫持了 window.postMessage 方法并注入了自定义方法?

documentation中提到了这个:

设置此属性会将 postMessage 全局注入到您的 webview,但仍会调用 postMessage 的预先存在的值。

也许这是错误的,这就是问题所在?

【问题讨论】:

我也有同样的问题,花了一整天的时间寻找解决方法,但是没有,正在处理一个拉取请求,也许我们会得到一些解决方案。 github.com/facebook/react-native/pull/10941 【参考方案1】:

我遇到了同样的问题,并通过将事件侦听器添加到文档而不是窗口来解决它。变化:

window.addEventListener("message", ...

到:

document.addEventListener("message", ...

【讨论】:

这行得通。谢谢。请记住,如果您还想支持常规浏览器,您应该同时定义 document.addEventListener("message", ...window.addEventListener("message", ... 谢谢,这对我很有帮助,节省了我不少时间,享受赏金吧。 谁能解释一下? @YuriyChachora 因为它是这样实现的:github.com/facebook/react-native/blob/master/ReactAndroid/src/… 对于 iOS:github.com/facebook/react-native/blob/master/React/Views/…【参考方案2】:

react-native-webview changes how this behavior works 的第 5 版。你现在想要:

window.ReactNativeWebView.postMessage(data);

【讨论】:

成功了。聪明的答案:) 很好的答案。帮我解决了! 帮我解决了! 为我工作,非常感谢【参考方案3】:

添加浏览器特定的事件监听器

在 Android 中

 document.addEventListener("message", function(event) 
       alert("This is a Entry Point Working in Android");
       init(event.data)
  );

在 iOS 中

 window.addEventListener("message", function(event) 
       alert("This is a Entry Point Working in iOS");
       init(event.data)
  );

【讨论】:

【参考方案4】:

实际上,监听器在不同的操作系统(如 iOS 和 Android)中的工作方式不同。所以你应该使用 document.addEventListener for Android 和 window.addEventListener for iOS。

if(navigator.appVersion.includes('Android'))
            document.addEventListener("message", function (data) 
               alert("you are in android OS");
            );
        
else 
            window.addEventListener("message", function (data) 
               alert("you are in android OS");               
             );
        

【讨论】:

我认为这实际上是已发布答案的副本。如果您认为可以添加一些内容,那么最好提交对现有答案的编辑。【参考方案5】:

您可以按照以下步骤操作 Pub/Sub =>>

第 1 步 => 在您的 React Native 应用程序中添加插件: https://github.com/react-native-webview/react-native-webview

第 2 步 => 在 ReactNative(Mobile Part) 中添加以下代码:

import React,  Component  from "react";
import  SafeAreaView, Text, TouchableHighlight  from "react-native";
import  WebView  from "react-native-webview";

class MobileWebView extends Component 
  state = ;

  onMessage = event => 
    const  data  = event.nativeEvent;
    this.setState( data );
  ;

  render() 
    return (
      <SafeAreaView style= flex: 1 >
        <TouchableHighlight
          style=
            padding: 10,
            backgroundColor: "red",
            width: "100%",
          
          onPress=() => 
            this.webview.postMessage("Message From React Native App to Web");
          
        >
          <Text>Send Message To Web</Text>
        </TouchableHighlight>
        <Text>Mobile: this.state.data</Text>
        <WebView
          ref=ref => 
            this.webview = ref;
          
          source= uri: "http://localhost:3000/" 
          onMessage=this.onMessage
          style= flex: 1 
        />
      </SafeAreaView>
    );
  


export default MobileWebView;

第 3 步 => 在 ReactJS(Web Part) 中添加以下代码:

import React,  Component  from "react";

class WebApp extends Component 
  state = ;
  componentDidMount() 
    document.addEventListener("message", event => 
      this.setState( msg: event.data );
    );
    window.addEventListener("message", event => 
      this.setState( msg: event.data );
    );
  

  render() 
    return (
      <div>
        <div>Web: this.state.msg</div>

        <button
          onClick=() => 
            window.ReactNativeWebView.postMessage(
              "Post message from web to Mobile",
              "*"
            );
          
        >
          Send Message To React Native(Mobile)
        </button>
      </div>
    );
  


export default WebApp;

一切顺利,现在您可以从移动设备向网络发送和接收消息,反之亦然。

Output Image

【讨论】:

【参考方案6】:

以上答案均不适用于 IOS,可能仍适用于 android 设备。这种方式适用于所有平台 -

在原生反应中:

const generateOnMessageFunction = data =>
    `(function() 
    window.WebViewBridge.onMessage($JSON.stringify(data));
  )()`;

class RNScreen extends React.Component
      private webView: RefObject<WebView> = createRef();
       render()
              return (
                    <WebView
                            javascriptEnabled
                            domStorageEnabled
                            bounces=false
                            ref=this.webView
                            onLoadEnd=() => 
                                this.postMessageTest(helloFromRN: true);
                            
                      />
              )
       

      private postMessageTest(data)
             this.webView.current.injectJavaScript(generateOnMessageFunction(data));
      


在JS端-

window.WebViewBridge = 
    onMessage: this._onMessage,
;
const event = new Event('WebViewBridge');
window.dispatchEvent(event);


// The data is not a string. It is an object.
private _onMessage(data: Object)
    // Should log "helloFromRN" on load.
    console.log(data)

【讨论】:

以上是关于React Native WebView postMessage 不起作用的主要内容,如果未能解决你的问题,请参考以下文章

WebView(react-native-webview)在 Expo SDK36 中获取错误代码 -1

React Native WebView 状态栏

React Native开发React Native控件之WebView组件详解以及实例使用(22)

React-native:如何自动保存 webview 当前网页?

WebView 不一致地显示白屏 react-native

有啥方法可以在 react-native-webview 中禁用 hapticFeedback