Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WebView] onMessage failing when there are JS warnings and errors on the page #10865

Closed
raiderrobert opened this issue Nov 10, 2016 · 92 comments
Closed

Comments

@raiderrobert
Copy link

@raiderrobert raiderrobert commented Nov 10, 2016

Description

I'm receiving this error (same as screenshot below):

Setting onMessage on a WebView overrides existing values of window.postMessage, 
but a previous value was defined.

screen shot 2016-11-10 at 3 33 31 pm

That specific error message is found in the code base here: https://github.com/facebook/react-native/blob/master/React/Views/RCTWebView.m#L286

Implementation

I followed the example at this link for onMessage at this link: http://facebook.github.io/react-native/releases/0.37/docs/webview.html#examples

I made a callable respondToOnMessage and injected some JavaScript.

class MessagingTest extends React.Component {

    respondToOnMessage = e =>{
        console.log(e);
    };

    render() {
        const jsCode = `window.postMessage('test');`;

        return (
        <WebView
        injectedJavaScript={jsCode}
        source={uri: 'https://www.foo.com/'}}
        onMessage={this.respondToOnMessage}
        />
        )
    }
}

Reproduction

I load the app with this example and I have it pointed to a website (rather not say which one. Sorry.) And the website is emitting 2 errors into the Chrome console when I go there.

(index):994 A Parser-blocking, cross-origin script, http://example.com/thing.js, is invoked via document.write. This may be blocked by the browser if the device has poor network connectivity.

widgets.js:8 Uncaught TypeError: Cannot set property '[object Array]' of undefined(…)

Other websites like google.com and github.com are just fine. If you want to replicate it, change the uri to yahoo.com

Additional Information

  • React Native version: 0.37
  • Platform: iOS 10.1, iPhone 6 emulator
  • Operating System: Mac OSX Sierra 10.12.1
@raiderrobert
Copy link
Author

@raiderrobert raiderrobert commented Nov 10, 2016

I should also add that I attempted to replicate the error on Android 7.0 and API 24 using a Nexus_5x emulator, and I got NO error. So this seems to be a platform specific error.

@sreucherand
Copy link

@sreucherand sreucherand commented Nov 11, 2016

I'm getting the same error. Seems like this exception is thrown when window.postMessage has been overwritten. But since webViewDidFinishLoad is called multiple times, it tries to overwrite window.postMessage over and over. Not sure though. Can we have you expertise @jacobp100?

@jacobp100
Copy link
Contributor

@jacobp100 jacobp100 commented Nov 11, 2016

It’s because the page you’re visiting is overriding postMessage, which may be due to a shim. Showing an error was chosen over invoking the shim’s value of postMessage when you call the value of postMessage that we set.

I thought I’d made it easier to workaround this problem, but it looks like that won’t work. The best you can do at the moment, which is an awful hack, is,

injectedJavaScript="window.postMessage = String(Object.hasOwnProperty).replace('hasOwnProperty', 'postMessage');"

Or just fork the project and remove the code you pointed to. Whatever’s easiest for you!

Ping @satya164 for input on how to resolve.

@sreucherand
Copy link

@sreucherand sreucherand commented Nov 11, 2016

Well, when I try String(window.postMessage) === String(Object.hasOwnProperty).replace('hasOwnProperty', 'postMessage') on the page I visit, it returns true, so I am guessing postMessage has not been overridden.

@jacobp100
Copy link
Contributor

@jacobp100 jacobp100 commented Nov 11, 2016

Oh I see. The JS is injected after postMessage is overwritten. Your best bet is to fork it then, and I’ll see what I can do about getting this fixed! Sorry. :(

@persyl
Copy link

@persyl persyl commented Nov 20, 2016

I have same error, without injecting any javascript to WebView - just setting WebView-properties:

source={require('../lib/html/somefile.html')}
onMessage={() => console.log('Hello World')}

and in my ../lib/html/somefile.html' I have javascript code doing both window.postMessage() and document.addEventListener("message",.......

Everything worked fine when I had the HTML in a variable "someHtml", like:
source={{html: someHtml}}

So difference seem to be when changing source to HTML-file instead of HTML-string.

Still for me I had other reasons, not related to this, why I really need to read HTML from file instead of string so it would be great to get this issue fixed.

@cbcye
Copy link

@cbcye cbcye commented Nov 20, 2016

+1, still has this problem

@jacobp100
Copy link
Contributor

@jacobp100 jacobp100 commented Nov 20, 2016

There is an ongoing discussion in #10941 for the best way to go forward with this.

It won't be in the next release or probably the release after. If you need this fixed now, fork the project and use the fix in the PR.

@lealife
Copy link

@lealife lealife commented Dec 19, 2016

+1, I'm getting the same error. When there is a iframe on web, it occurs the same error

@varhp
Copy link

@varhp varhp commented Dec 21, 2016

+1,encounter this problem

@jacobp100
Copy link
Contributor

@jacobp100 jacobp100 commented Dec 21, 2016

Again, there is a pr for this. We're aware this problem is affecting a lot of people.

@edencakir
Copy link

@edencakir edencakir commented Dec 26, 2016

+1 getting the same error.

@kyle-ilantzis
Copy link

@kyle-ilantzis kyle-ilantzis commented Dec 31, 2016

injectedJavascript should instead be the following

(function() {
  var originalPostMessage = window.postMessage;

  var patchedPostMessage = function(message, targetOrigin, transfer) { 
    originalPostMessage(message, targetOrigin, transfer);
  };

  patchedPostMessage.toString = function() { 
    return String(Object.hasOwnProperty).replace('hasOwnProperty', 'postMessage'); 
  };

  window.postMessage = patchedPostMessage;
})();

And then it works! 😄

And if any one is interested, in my code instead of writing a giant string I did the following

const patchPostMessageFunction = function() {
  var originalPostMessage = window.postMessage;

  var patchedPostMessage = function(message, targetOrigin, transfer) { 
    originalPostMessage(message, targetOrigin, transfer);
  };

  patchedPostMessage.toString = function() { 
    return String(Object.hasOwnProperty).replace('hasOwnProperty', 'postMessage');
  };

  window.postMessage = patchedPostMessage;
};

const patchPostMessageJsCode = '(' + String(patchPostMessageFunction) + ')();';

...

<WebView injectedJavaScript={patchPostMessageJsCode} />
@mschipperheyn
Copy link

@mschipperheyn mschipperheyn commented Jan 21, 2017

@kyle-ilantzis tried this with RN 0.38.1, but still get the Red Screen. What version of RN are you on?

@kyle-ilantzis
Copy link

@kyle-ilantzis kyle-ilantzis commented Jan 21, 2017

@mschipperheyn I am using RN 0.39.0

The ios webview code between 0.39 and 0.38 is not different so it is odd you still get the red screen.

https://github.com/facebook/react-native/blob/0.39-stable/React/Views/RCTWebView.m#L280

https://github.com/facebook/react-native/blob/0.38-stable/React/Views/RCTWebView.m#L280

@abeauvois
Copy link

@abeauvois abeauvois commented Jan 30, 2017

Same issue with RN 0.40, as soon as we add 'onMessage' props to the WebView.

@hadrienj
Copy link

@hadrienj hadrienj commented Mar 9, 2017

Same issue with RN 0.42 with a WebView (without js injection) when I load PouchDB (6.1.2).

@skrobek
Copy link

@skrobek skrobek commented Mar 21, 2017

@kyle-ilantzis I'm trying your solution with RN 0.42 but after using it I can't see onMessage callback:

pushCredentials = () => {
  if (this.webview) {
    this.webview.postMessage('Post message triggered');
  }
}


onMessage = (e) => {
    this.setState({ postMessage: e.nativeEvent.data });
};

// in render method
<WebView
    ref={(ref) => { this.webview = ref; }}
    source={{ uri}}
    injectedJavaScript={patchPostMessageJsCode}
    onMessage={this.onMessage}
/>
@kyle-ilantzis
Copy link

@kyle-ilantzis kyle-ilantzis commented Mar 21, 2017

@skrobek Do you mean pushCredentials() no longer causes onMessage() to be called?

  1. Should it not be:
    onMessage={this.onMessage.bind(this)}

  2. I never thought that when posting a message from react-native to the webview the webview would call its own onMessage. I thought onMessage is only called when JS code in the webview calls window.postMessage(...)

@skrobek
Copy link

@skrobek skrobek commented Mar 21, 2017

@kyle-ilantzis Look at the docs example:

class MessagingTest extends React.Component {
  webview = null

  state = {
    messagesReceivedFromWebView: 0,
    message: '',
  }

  onMessage = e => this.setState({
    messagesReceivedFromWebView: this.state.messagesReceivedFromWebView + 1,
    message: e.nativeEvent.data,
  })

  postMessage = () => {
    if (this.webview) {
      this.webview.postMessage('"Hello" from React Native!');
    }
  }

  render(): ReactElement<any> {
    const {messagesReceivedFromWebView, message} = this.state;

    return (
      <View style={[styles.container, { height: 200 }]}>
        <View style={styles.container}>
          <Text>Messages received from web view: {messagesReceivedFromWebView}</Text>
          <Text>{message || '(No message)'}</Text>
          <View style={styles.buttons}>
            <Button text="Send Message to Web View" enabled onPress={this.postMessage} />
          </View>
        </View>
        <View style={styles.container}>
          <WebView
            ref={webview => { this.webview = webview; }}
            style={{
              backgroundColor: BGWASH,
              height: 100,
            }}
            source={require('./messagingtest.html')}
            onMessage={this.onMessage}
          />
        </View>
      </View>
    );
  }
}
@kyle-ilantzis
Copy link

@kyle-ilantzis kyle-ilantzis commented Mar 21, 2017

@skrobek Oh no 😱

My objective was to have the JS code in the webview talk to react-native. It was not to have react-native talk to itself through a webview.

patchPostMessage achieved my objective, no more red screen on ios when setting the onMessage property of a webview. JS code in an IOS webview could then talk to react-native

@skrobek
Copy link

@skrobek skrobek commented Mar 21, 2017

@kyle-ilantzis Yeah. Now I have huge problem because docs cause red screen and your solution helps with the red screen but block webview.postMessage - no idea what to do ;-)

@davidhellsing
Copy link

@davidhellsing davidhellsing commented Mar 24, 2017

You could wait for the onLoad before passing onMessage into the component (passing null until the onLoad triggers).

It worked for us, but we had to implement a simple queue in the webview that collects posts until the onLoad has triggered, which then triggers another onLoad inside the webview using injectJavaScript...

  onLoad(e) {
    // onload is called multiple times...
    if ( this.state.loaded ) {
      return
    }
    this.setState({ loaded: true }, () => this.bridge.injectJavaScript('window.onLoad()'))
  }
  onMessage(payload) {
    console.log('got message from web view', payload)
  }
  render() {
    return (
      <WebView
        onLoad={this.onLoad}
        ref={n => this.bridge = n} 
        source={require('../assets/bridge.html')} 
        javaScriptEnabled={true} 
        onMessage={this.state.loaded ? this.onMessage.bind(this) : null} 
      />
    )
  }
@kyle-ilantzis
Copy link

@kyle-ilantzis kyle-ilantzis commented Mar 24, 2017

@davidhellsing interesting to use the webview onLoad. With the injectedJavascipt solution I still needed to implement a queue in the webview

@axten
Copy link

@axten axten commented Apr 13, 2017

The Workarounds are not working for me.
Is someone working on an fix for that?

@davidhellsing
Copy link

@davidhellsing davidhellsing commented May 19, 2017

If you feel brave, use a shell script to rename the native postMessage:

sed -i '' '/@"window.originalPostMessage = window.postMessage;"/d' node_modules/react-native/React/Views/RCTWebView.m
sed -i '' 's/  "window.postMessage = function(data) {/@"window.nativePostMessage = function(data) {/' node_modules/react-native/React/Views/RCTWebView.m
sed -i '' '/"window.originalPostMessage = window.postMessage," +/d' node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/views/webview/ReactWebViewManager.java
sed -i '' 's/"window.postMessage = function(data) {" +/"window.nativePostMessage = function(data) {" +/' node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/views/webview/ReactWebViewManager.java

After running this script (you will need to do it after each yarn npm install), you can simply use:

window.nativePostMessage('it works')

inside your webView. IMO, this should be done a long time ago... there is a PR here for basically the same thing: https://github.com/facebook/react-native/pull/12997/files?diff=split

@0x6e6562
Copy link

@0x6e6562 0x6e6562 commented May 25, 2017

@davidhellsing Nice patch :-)

This appears to be working for me on iOS with RN 0.44 (haven't tried it on Android yet).

ivank added a commit to ivank/react-native that referenced this issue Jul 19, 2018
The current way we're testing if postMessage has been changed is no
longer valid. Lodash has already changed the way they test agianst this,
as it no longer works in blink (thow continiues to work in webkit)

In chrome browser (Version 65.0.3325.181 (Official Build) (64-bit)) console type:

```js
String(window.postMessage) === String(Object.hasOwnProperty).replace('hasOwnProperty', 'postMessage')
```

It still works in safari (Version 11.0.3 (13604.5.6))

A simplified version of how lodash are testing aginst it
https://github.com/lodash/lodash/blob/4.0.1-npm-packages/lodash.isnative/index.js

With a simpler description about this method can be found here:
https://davidwalsh.name/detect-native-function

Running:

```js
RegExp('^' +
  String(Object.prototype.toString)
  .replace(/[.*+?^${}()|[\]\/\\]/g, '\\$&')
  .replace(/toString|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$'
).test(String(window.postMessage))
```

Works correctly in both chrome and safari.

Affected issues:

facebook#10865 - some hacks were
seggested here to sidestep this issue. This PR should fix it outright
@schlaegerz
Copy link

@schlaegerz schlaegerz commented Jul 20, 2018

No matter what I do, if I try to implement onMessage it breaks the website.

I am trying to render a meteor app in the Webview, and it depends on postMessage just working normally.

This would be solved if we could just override the name of the postMessage, like lettings us specify a namespace window.reactNative.postMessage or just change it to window.RNPostmessage it doesn't even need to be a default, but giving the option to change it would fix all these problems.

@laukaichung
Copy link

@laukaichung laukaichung commented Sep 8, 2018

@jneuendorf
You are right. I have a quill editor loaded in the WebView. The problem only occurs when the content contains a youtube video.

@Titozzz
Copy link
Contributor

@Titozzz Titozzz commented Sep 9, 2018

Hi there, we are migrating all the WebView issues to the new repository https://github.com/react-native-community/react-native-webview. Correct me if I'm wrong but this does not seem to happen with the new WKWebview implementation. If it does, feel free to open an issue directly on the new repository and link that issue to it!
Thanks,

@laukaichung
Copy link

@laukaichung laukaichung commented Sep 13, 2018

@Titozzz
I use react-native-navigation and react-native-link no longer applies changes on MainApplication.java for Android. When I install libraries I have to add the packages manually.

Do I need to add the webview package to the createAdditionalReactPackages() method?
I ran react-native link react-native-webview but there are no changes on the file.

@Titozzz
Copy link
Contributor

@Titozzz Titozzz commented Sep 13, 2018

@stonecold123 please open an issue on the new repo

@CharlesStover
Copy link

@CharlesStover CharlesStover commented Sep 23, 2018

For anyone still struggling with this, I released rn-webview on NPM to solve this exact problem (open-sourced on GitHub). My team and myself are unable or unwilling to eject from our Expo implementation in order to use the community edition linked a few posts above. If you are able to do so, I'd recommend that option. If you want to maintain a purely JavaScript, out-of-the-box Expo experience, the rn-webview package is for you.

I wrote a walkthrough for how it works on Medium. Of course the implementation has to have drawbacks, and the way it works may not be acceptable for your use case. The biggest deal is that, instead of relying on native window.postMessage function, it instead manipulates the history (history.pushState) so that it can listen to the navigation state change event (which is supported by both Android and iOS). Feel free to suggest better implementations in the Issues for the repo or fork and adjust not altering the navigation state is crucial to your project.

Hope this helps!

@Titozzz
Copy link
Contributor

@Titozzz Titozzz commented Sep 24, 2018

@CharlesStover To goal of the community repo is to fix theses issues that were never fixed. The slimmening should allow everyone to move faster. We, of course, hope that expo will choose to add all the slimmening packages into their releases so that you don't have to depend on such workarounds

@Titozzz Titozzz closed this Sep 24, 2018
@AdamZaczek
Copy link

@AdamZaczek AdamZaczek commented Jan 23, 2019

injectedJavascript should instead be the following

(function() {
  var originalPostMessage = window.postMessage;

  var patchedPostMessage = function(message, targetOrigin, transfer) { 
    originalPostMessage(message, targetOrigin, transfer);
  };

  patchedPostMessage.toString = function() { 
    return String(Object.hasOwnProperty).replace('hasOwnProperty', 'postMessage'); 
  };

  window.postMessage = patchedPostMessage;
})();

And then it works! 😄

And if any one is interested, in my code instead of writing a giant string I did the following

const patchPostMessageFunction = function() {
  var originalPostMessage = window.postMessage;

  var patchedPostMessage = function(message, targetOrigin, transfer) { 
    originalPostMessage(message, targetOrigin, transfer);
  };

  patchedPostMessage.toString = function() { 
    return String(Object.hasOwnProperty).replace('hasOwnProperty', 'postMessage');
  };

  window.postMessage = patchedPostMessage;
};

const patchPostMessageJsCode = '(' + String(patchPostMessageFunction) + ')();';

...

<WebView injectedJavaScript={patchPostMessageJsCode} />

You man are my hero! This is so simple and eloquent. It works for Expo 31 even when using iframes

@olegongit
Copy link

@olegongit olegongit commented Feb 6, 2019

For me it helped to use 'useWebKit' prop on a WebView.

harutyundr added a commit to addonslab/react-native-autoheight-webview that referenced this issue Feb 10, 2019
@princeTPG
Copy link

@princeTPG princeTPG commented Feb 12, 2019

This issue will not occur is you use "useWebKit" prop of webview, that will use WK webview instead of UI webview in case of IOS.
But in case if you don't want to use WK webview, then below is the sample JS code that you can inject in you Webview with "injectedJavaScript" prop.

  `(function () {
      let originalPostMessage = window.postMessage;
      let patchedPostMessage = function(message, targetOrigin, transfer, ...other) { 
        originalPostMessage(message, targetOrigin, transfer, ...other);
      };

      patchedPostMessage.toString = function() { 
        return String(Object.hasOwnProperty).replace('hasOwnProperty', 'postMessage');
      };

      window.postMessage = patchedPostMessage;
    })()`

The above code did nothing just patched window.postMessage function, the above issue will not appear.

@Angelk90
Copy link

@Angelk90 Angelk90 commented Apr 1, 2019

@AdamZaczek , @princeTPG :

I can't get it to work properly, you can give an example that can work on https://snack.expo.io?

I did something like that, but it seems that it doesn't work anymore.

Code:

render() {
    const jsCodeOpenload = `
        (function ready() {
          function whenRNPostMessageReady(cb) {
            if (postMessage.length === 1) cb();
            else setTimeout(function() { whenRNPostMessageReady(cb) }, 100);
          }
          whenRNPostMessageReady(function() {
            postMessage(document.getElementById('olvideo_html5_api').innerHTML);
          });
        })();`;
    return (
      <View>
        {this.state.urlOpenload != '' && (
          <WebView
            source={{
              uri: this.state.urlOpenload,
            }}
            onMessage={evt => {
              this.setState({ code: evt.nativeEvent.data });
            }}
            injectedJavaScript={jsCodeOpenload}
            javaScriptEnabled
            style={{ flex: 1 }}
          />
        )}
      </View>
    );
  }

onMessage seems to receive nothing more, even if it worked before.

@TfADrama
Copy link

@TfADrama TfADrama commented May 22, 2019

This issue will not occur is you use "useWebKit" prop of webview, that will use WK webview instead of UI webview in case of IOS.
But in case if you don't want to use WK webview, then below is the sample JS code that you can inject in you Webview with "injectedJavaScript" prop.

  `(function () {
      let originalPostMessage = window.postMessage;
      let patchedPostMessage = function(message, targetOrigin, transfer, ...other) { 
        originalPostMessage(message, targetOrigin, transfer, ...other);
      };

      patchedPostMessage.toString = function() { 
        return String(Object.hasOwnProperty).replace('hasOwnProperty', 'postMessage');
      };

      window.postMessage = patchedPostMessage;
    })()`

The above code did nothing just patched window.postMessage function, the above issue will not appear.

The patched script makes my onMessage to be always called twice in iOS when i do a click event...
The useWebKit prop was the only way, at least for now...

@kenobi91
Copy link

@kenobi91 kenobi91 commented Jun 27, 2019

If you still have this issue you can use code from above, to prevent this error like this:

`const patchPostMessageFunction = function() {
var originalPostMessage = window.postMessage;

var patchedPostMessage = function(message, targetOrigin, transfer) {
originalPostMessage(message, targetOrigin, transfer);
};

patchedPostMessage.toString = function() {
return String(Object.hasOwnProperty).replace('hasOwnProperty', 'postMessage');
};

window.postMessage = patchedPostMessage;
};`

Then you can append your own JS injection code like this:

<WebView injectedJavaScript={'(' + String(patchPostMessageFunction) + ')();' + injectedJavaScript}/>

This will prevent error from above but also this will prevent in some cases to use window.postMessage from your injected JS code. To go around this just wrap window.postMessage(msg) in timeout like this:
setTimeout(() => { window.postMessage(JSON.stringify(postMessage)); }, 100);

@Rafaell416
Copy link

@Rafaell416 Rafaell416 commented Jul 29, 2019

injectedJavascript should instead be the following

(function() {
  var originalPostMessage = window.postMessage;

  var patchedPostMessage = function(message, targetOrigin, transfer) { 
    originalPostMessage(message, targetOrigin, transfer);
  };

  patchedPostMessage.toString = function() { 
    return String(Object.hasOwnProperty).replace('hasOwnProperty', 'postMessage'); 
  };

  window.postMessage = patchedPostMessage;
})();

And then it works! 😄

And if any one is interested, in my code instead of writing a giant string I did the following

const patchPostMessageFunction = function() {
  var originalPostMessage = window.postMessage;

  var patchedPostMessage = function(message, targetOrigin, transfer) { 
    originalPostMessage(message, targetOrigin, transfer);
  };

  patchedPostMessage.toString = function() { 
    return String(Object.hasOwnProperty).replace('hasOwnProperty', 'postMessage');
  };

  window.postMessage = patchedPostMessage;
};

const patchPostMessageJsCode = '(' + String(patchPostMessageFunction) + ')();';

...

<WebView injectedJavaScript={patchPostMessageJsCode} />

Awesome man, if you come to Colombia I'll invite u some Empanadas.

@kckunal2612
Copy link

@kckunal2612 kckunal2612 commented Sep 30, 2019

injectedJavascript should instead be the following

(function() {
  var originalPostMessage = window.postMessage;

  var patchedPostMessage = function(message, targetOrigin, transfer) { 
    originalPostMessage(message, targetOrigin, transfer);
  };

  patchedPostMessage.toString = function() { 
    return String(Object.hasOwnProperty).replace('hasOwnProperty', 'postMessage'); 
  };

  window.postMessage = patchedPostMessage;
})();

And then it works! 😄

And if any one is interested, in my code instead of writing a giant string I did the following

const patchPostMessageFunction = function() {
  var originalPostMessage = window.postMessage;

  var patchedPostMessage = function(message, targetOrigin, transfer) { 
    originalPostMessage(message, targetOrigin, transfer);
  };

  patchedPostMessage.toString = function() { 
    return String(Object.hasOwnProperty).replace('hasOwnProperty', 'postMessage');
  };

  window.postMessage = patchedPostMessage;
};

const patchPostMessageJsCode = '(' + String(patchPostMessageFunction) + ')();';

...

<WebView injectedJavaScript={patchPostMessageJsCode} />

Is there an updated version of this answer which will work with the new version of react-native-webview ? I am unable to receive messages in onMessage() on both iOS and Android. :(

@kckunal2612
Copy link

@kckunal2612 kckunal2612 commented Sep 30, 2019

Is there an updated version of this answer which will work with the new version of react-native-webview ? I am unable to receive messages in onMessage() on both iOS and Android. :(

Answering my own question here for everyone else's reference -

(See - https://github.com/react-native-community/react-native-webview/releases/tag/v5.0.0)

// Apply fix for newer react-native-webview not supporting window.postMessage
const webViewFix = function() {
  window.postMessage = function(data) {
    window.ReactNativeWebView.postMessage(data);
  };
};
const windowPostMessageFix = '(' + String(webViewFix) + ')();';

const patchPostMessageFunction = function() {
  const originalPostMessage = window.postMessage;

  const patchedPostMessage = function(message, targetOrigin, transfer) {
    originalPostMessage(message, targetOrigin, transfer);
  };

  patchedPostMessage.toString = function() {
    return String(Object.hasOwnProperty).replace(
      'hasOwnProperty',
      'postMessage',
    );
  };

  window.postMessage = patchedPostMessage;
};

const patchPostMessageJsCode = '(' + String(patchPostMessageFunction) + ')();';

Make sure you call windowPostMessageFix function first and then your second function -

<WebView
 injectedJavaScript={[
                windowPostMessageFix,
                patchPostMessageJsCode
              ].join('')}

I hope it helps ! Thanks !

@DevArenaCN
Copy link

@DevArenaCN DevArenaCN commented Oct 7, 2019

Is there an updated version of this answer which will work with the new version of react-native-webview ? I am unable to receive messages in onMessage() on both iOS and Android. :(

Answering my own question here for everyone else's reference -

(See - https://github.com/react-native-community/react-native-webview/releases/tag/v5.0.0)

// Apply fix for newer react-native-webview not supporting window.postMessage
const webViewFix = function() {
  window.postMessage = function(data) {
    window.ReactNativeWebView.postMessage(data);
  };
};
const windowPostMessageFix = '(' + String(webViewFix) + ')();';

const patchPostMessageFunction = function() {
  const originalPostMessage = window.postMessage;

  const patchedPostMessage = function(message, targetOrigin, transfer) {
    originalPostMessage(message, targetOrigin, transfer);
  };

  patchedPostMessage.toString = function() {
    return String(Object.hasOwnProperty).replace(
      'hasOwnProperty',
      'postMessage',
    );
  };

  window.postMessage = patchedPostMessage;
};

const patchPostMessageJsCode = '(' + String(patchPostMessageFunction) + ')();';

Make sure you call windowPostMessageFix function first and then your second function -

<WebView
 injectedJavaScript={[
                windowPostMessageFix,
                patchPostMessageJsCode
              ].join('')}

I hope it helps ! Thanks !

This did solve the issue with the red screen, but when I tried to post data back from my frontend code calling window.postMessage('some stuff'. '*') I got error TypeError: undefined is not an object (evaluating 'window.ReactNativeWebView.postMessage') Any ideas?

@kckunal2612
Copy link

@kckunal2612 kckunal2612 commented Oct 8, 2019

Is there an updated version of this answer which will work with the new version of react-native-webview ? I am unable to receive messages in onMessage() on both iOS and Android. :(

Answering my own question here for everyone else's reference -
(See - https://github.com/react-native-community/react-native-webview/releases/tag/v5.0.0)

// Apply fix for newer react-native-webview not supporting window.postMessage
const webViewFix = function() {
  window.postMessage = function(data) {
    window.ReactNativeWebView.postMessage(data);
  };
};
const windowPostMessageFix = '(' + String(webViewFix) + ')();';

const patchPostMessageFunction = function() {
  const originalPostMessage = window.postMessage;

  const patchedPostMessage = function(message, targetOrigin, transfer) {
    originalPostMessage(message, targetOrigin, transfer);
  };

  patchedPostMessage.toString = function() {
    return String(Object.hasOwnProperty).replace(
      'hasOwnProperty',
      'postMessage',
    );
  };

  window.postMessage = patchedPostMessage;
};

const patchPostMessageJsCode = '(' + String(patchPostMessageFunction) + ')();';

Make sure you call windowPostMessageFix function first and then your second function -

<WebView
 injectedJavaScript={[
                windowPostMessageFix,
                patchPostMessageJsCode
              ].join('')}

I hope it helps ! Thanks !

This did solve the issue with the red screen, but when I tried to post data back from my frontend code calling window.postMessage('some stuff'. '*') I got error TypeError: undefined is not an object (evaluating 'window.ReactNativeWebView.postMessage') Any ideas?

I tested my app on Lollipop and it crashes due to a WebView issue listed here -
react-native-community/react-native-webview#858

As a result, our company is now moving away from React Native for Android. Sadly, there are too many breaking changes and too many security vulnerabilities in third party libraries.

@facebook facebook locked as resolved and limited conversation to collaborators Dec 11, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

You can’t perform that action at this time.