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

Open
raiderrobert opened this Issue Nov 10, 2016 · 79 comments

Comments

Projects
None yet
@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

This comment has been minimized.

Show comment
Hide comment
@raiderrobert

raiderrobert 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.

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.

@hramos hramos added the 🔷iOS label Nov 10, 2016

@sreucherand

This comment has been minimized.

Show comment
Hide comment
@sreucherand

sreucherand 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?

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

This comment has been minimized.

Show comment
Hide comment
@jacobp100

jacobp100 Nov 11, 2016

Contributor

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.

Contributor

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

This comment has been minimized.

Show comment
Hide comment
@sreucherand

sreucherand 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.

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

This comment has been minimized.

Show comment
Hide comment
@jacobp100

jacobp100 Nov 11, 2016

Contributor

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. :(

Contributor

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

This comment has been minimized.

Show comment
Hide comment
@persyl

persyl 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.

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

This comment has been minimized.

Show comment
Hide comment
@cbcye

cbcye Nov 20, 2016

+1, still has this problem

cbcye commented Nov 20, 2016

+1, still has this problem

@jacobp100

This comment has been minimized.

Show comment
Hide comment
@jacobp100

jacobp100 Nov 20, 2016

Contributor

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.

Contributor

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

This comment has been minimized.

Show comment
Hide comment
@lealife

lealife Dec 19, 2016

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

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

This comment has been minimized.

Show comment
Hide comment
@varhp

varhp Dec 21, 2016

+1,encounter this problem

varhp commented Dec 21, 2016

+1,encounter this problem

@jacobp100

This comment has been minimized.

Show comment
Hide comment
@jacobp100

jacobp100 Dec 21, 2016

Contributor

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

Contributor

jacobp100 commented Dec 21, 2016

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

@edencakir

This comment has been minimized.

Show comment
Hide comment
@edencakir

edencakir Dec 26, 2016

+1 getting the same error.

edencakir commented Dec 26, 2016

+1 getting the same error.

@kyle-ilantzis

This comment has been minimized.

Show comment
Hide comment
@kyle-ilantzis

kyle-ilantzis 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} />

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

This comment has been minimized.

Show comment
Hide comment
@mschipperheyn

mschipperheyn 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?

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

This comment has been minimized.

Show comment
Hide comment
@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

This comment has been minimized.

Show comment
Hide comment
@abeauvois

abeauvois Jan 30, 2017

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

abeauvois commented Jan 30, 2017

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

@hadrienj

This comment has been minimized.

Show comment
Hide comment
@hadrienj

hadrienj Mar 9, 2017

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

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

This comment has been minimized.

Show comment
Hide comment
@skrobek

skrobek 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}
/>

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

This comment has been minimized.

Show comment
Hide comment
@kyle-ilantzis

kyle-ilantzis 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(...)

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

This comment has been minimized.

Show comment
Hide comment
@skrobek

skrobek 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>
    );
  }
}

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

This comment has been minimized.

Show comment
Hide comment
@kyle-ilantzis

kyle-ilantzis 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

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

This comment has been minimized.

Show comment
Hide comment
@skrobek

skrobek 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 ;-)

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

This comment has been minimized.

Show comment
Hide comment
@davidhellsing

davidhellsing 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} 
      />
    )
  }

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

This comment has been minimized.

Show comment
Hide comment
@kyle-ilantzis

kyle-ilantzis Mar 24, 2017

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

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

This comment has been minimized.

Show comment
Hide comment
@axten

axten Apr 13, 2017

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

axten commented Apr 13, 2017

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

@davidhellsing

This comment has been minimized.

Show comment
Hide comment
@davidhellsing

davidhellsing 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

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

This comment has been minimized.

Show comment
Hide comment
@0x6e6562

0x6e6562 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).

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).

@shenzhenjinma

This comment has been minimized.

Show comment
Hide comment

shenzhenjinma commented Jun 7, 2017

please see http://68xg.com/reactnative/82.html

@axten

This comment has been minimized.

Show comment
Hide comment
@axten

axten Jun 8, 2017

@davidhellsing this sed script is not working on android
it seems that react native android uses pre compiled sources and the change to the java file has no effect.
this is where i go so far https://facebook.github.io/react-native/docs/android-building-from-source.html

messing the second day in a row with this bug...shit

axten commented Jun 8, 2017

@davidhellsing this sed script is not working on android
it seems that react native android uses pre compiled sources and the change to the java file has no effect.
this is where i go so far https://facebook.github.io/react-native/docs/android-building-from-source.html

messing the second day in a row with this bug...shit

@davidgross

This comment has been minimized.

Show comment
Hide comment
@davidgross

davidgross Jun 9, 2017

Just ran into this today, would really like to have a resolution for our project.

davidgross commented Jun 9, 2017

Just ran into this today, would really like to have a resolution for our project.

@untungs

This comment has been minimized.

Show comment
Hide comment
@untungs

untungs Jun 10, 2017

In my project this red screen doesn't appear for non-debug build and the web page I'm using still works without any issue. While in debug build I could just dismiss the red screen and continue. But It's kinda annoying and who knows when an issue's gonna popping up in non-debug build. Please fix.

untungs commented Jun 10, 2017

In my project this red screen doesn't appear for non-debug build and the web page I'm using still works without any issue. While in debug build I could just dismiss the red screen and continue. But It's kinda annoying and who knows when an issue's gonna popping up in non-debug build. Please fix.

@MrLoh

This comment has been minimized.

Show comment
Hide comment
@MrLoh

MrLoh Jun 10, 2017

Is this gonna be fixed, it's super annoying and there are plenty suggestions for a solution?.

MrLoh commented Jun 10, 2017

Is this gonna be fixed, it's super annoying and there are plenty suggestions for a solution?.

@probedb

This comment has been minimized.

Show comment
Hide comment
@probedb

probedb Jun 12, 2017

Just ran into this today too. I can see the website load in the app and then I get this error. Has completely halted work on our app.

probedb commented Jun 12, 2017

Just ran into this today too. I can see the website load in the app and then I get this error. Has completely halted work on our app.

@MrLoh

This comment has been minimized.

Show comment
Hide comment
@MrLoh

MrLoh Jun 12, 2017

the solution from @kyle-ilantzis works well. I just wrote a patched WebView class for myself, feel free to use. This class also automatically JSON encodes and decodes the messages and tweaked the source attribute to my liking.

import React from 'react'
import { WebView } from 'react-native'

// fix https://github.com/facebook/react-native/issues/10865
const patchPostMessageJsCode = `(${String(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
})})();`

export default class MessageWebView extends React.Component {
    constructor(props) {
        super(props)
        this.postMessage = this.postMessage.bind(this)
    }
    postMessage(action) {
        this.WebView.postMessage(JSON.stringify(action))
    }
    render() {
        const { html, source, url, onMessage, ...props } = this.props
        return (
            <WebView
                {...props}
                javaScriptEnabled
                injectedJavaScript={patchPostMessageJsCode}
                source={source ? source : html ? { html } : url}
                ref={x => {this.WebView = x}}
                onMessage={e => onMessage(JSON.parse(e.nativeEvent.data))}
            />
        )
    }
}

MrLoh commented Jun 12, 2017

the solution from @kyle-ilantzis works well. I just wrote a patched WebView class for myself, feel free to use. This class also automatically JSON encodes and decodes the messages and tweaked the source attribute to my liking.

import React from 'react'
import { WebView } from 'react-native'

// fix https://github.com/facebook/react-native/issues/10865
const patchPostMessageJsCode = `(${String(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
})})();`

export default class MessageWebView extends React.Component {
    constructor(props) {
        super(props)
        this.postMessage = this.postMessage.bind(this)
    }
    postMessage(action) {
        this.WebView.postMessage(JSON.stringify(action))
    }
    render() {
        const { html, source, url, onMessage, ...props } = this.props
        return (
            <WebView
                {...props}
                javaScriptEnabled
                injectedJavaScript={patchPostMessageJsCode}
                source={source ? source : html ? { html } : url}
                ref={x => {this.WebView = x}}
                onMessage={e => onMessage(JSON.parse(e.nativeEvent.data))}
            />
        )
    }
}
@probedb

This comment has been minimized.

Show comment
Hide comment
@probedb

probedb Jun 13, 2017

@kyle-ilantzis Am I missing something from my code? I have implemented it as per your example, I have put debug code into the site I use inside the WebView so I can see it sends the postMessage, however nothing happens in the react-native app :/

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) + ')();';

_onMessage(e) {
  deviceLog.log('_onMessage')

  const {messageType, messageData} = e.nativeEvent.data

  deviceLog.log(messageType, messageData)
  switch (messageType) {
    case'registeredUser':
      Intercom.registerIdentifiedUser({ userId: messageData.customerId })
      break;
    case'unregisteredUser':
      Intercom.registerUnidentifiedUser()
      break;
  }
}
render() {
  return (
    <View style={[styles.container]}>
      <LogView inverted={false} multiExpanded timeStampFormat='HH:mm:ss'></LogView>
      <WebView
        ref={WEBVIEW_REF}
        automaticallyAdjustContentInsets={false}
        style={styles.webView}
        source={{uri: this.state.url}}
        javaScriptEnabled
        domStorageEnabled
        decelerationRate="normal"
        startInLoadingState
        scalesPageToFit={this.state.scalesPageToFit}
        onShouldStartLoadWithRequest={this._onShouldStartLoadWithRequest}
        onNavigationStateChange={this._onNavigationStateChange}
        onMessage={this._onMessage}
        injectedJavaScript={patchPostMessageJsCode}
      />
    </View>
  )
}

The deviceLog above is not registering anything. I know it works as everything else that uses it works. Also in my constructor() I have:

this._onMessage = this._onMessage.bind(this)

Any thoughts anyone? It's the last step in my app that I need to do :) The postMessage() within the site calls:

window.postMessage({
  messageType: 'registeredUser',
  messageData: {customerId},
}, '*')

probedb commented Jun 13, 2017

@kyle-ilantzis Am I missing something from my code? I have implemented it as per your example, I have put debug code into the site I use inside the WebView so I can see it sends the postMessage, however nothing happens in the react-native app :/

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) + ')();';

_onMessage(e) {
  deviceLog.log('_onMessage')

  const {messageType, messageData} = e.nativeEvent.data

  deviceLog.log(messageType, messageData)
  switch (messageType) {
    case'registeredUser':
      Intercom.registerIdentifiedUser({ userId: messageData.customerId })
      break;
    case'unregisteredUser':
      Intercom.registerUnidentifiedUser()
      break;
  }
}
render() {
  return (
    <View style={[styles.container]}>
      <LogView inverted={false} multiExpanded timeStampFormat='HH:mm:ss'></LogView>
      <WebView
        ref={WEBVIEW_REF}
        automaticallyAdjustContentInsets={false}
        style={styles.webView}
        source={{uri: this.state.url}}
        javaScriptEnabled
        domStorageEnabled
        decelerationRate="normal"
        startInLoadingState
        scalesPageToFit={this.state.scalesPageToFit}
        onShouldStartLoadWithRequest={this._onShouldStartLoadWithRequest}
        onNavigationStateChange={this._onNavigationStateChange}
        onMessage={this._onMessage}
        injectedJavaScript={patchPostMessageJsCode}
      />
    </View>
  )
}

The deviceLog above is not registering anything. I know it works as everything else that uses it works. Also in my constructor() I have:

this._onMessage = this._onMessage.bind(this)

Any thoughts anyone? It's the last step in my app that I need to do :) The postMessage() within the site calls:

window.postMessage({
  messageType: 'registeredUser',
  messageData: {customerId},
}, '*')
@kyle-ilantzis

This comment has been minimized.

Show comment
Hide comment
@kyle-ilantzis

kyle-ilantzis Jun 13, 2017

@probedb so you no longer have the red error screen? Next problem is most likely that react native has not loaded into the webview.

Maybe the site calls postMessage before react native has attached hooks into the webview

To be sure that this is the reason, sourround your site's postMessage with a timeout

setTimeout(
function() { windown.postMessage(...) }
,
2000 )

You can get more details below (where I also particupated in the discussion ;) )

#11594

kyle-ilantzis commented Jun 13, 2017

@probedb so you no longer have the red error screen? Next problem is most likely that react native has not loaded into the webview.

Maybe the site calls postMessage before react native has attached hooks into the webview

To be sure that this is the reason, sourround your site's postMessage with a timeout

setTimeout(
function() { windown.postMessage(...) }
,
2000 )

You can get more details below (where I also particupated in the discussion ;) )

#11594

@probedb

This comment has been minimized.

Show comment
Hide comment
@probedb

probedb Jun 13, 2017

@kyle-ilantzis yep, the red screen has gone :) It appears to be in the react app I run in the WebView. For some reason although the code is running, it's not firing the postMessage. I tried a very simple test and it picks up the code. Thanks for the help 👍

probedb commented Jun 13, 2017

@kyle-ilantzis yep, the red screen has gone :) It appears to be in the react app I run in the WebView. For some reason although the code is running, it's not firing the postMessage. I tried a very simple test and it picks up the code. Thanks for the help 👍

zloybest added a commit to AllmaxTeam/react-native-intercom-webview that referenced this issue Dec 13, 2017

@Benorb

This comment has been minimized.

Show comment
Hide comment
@Benorb

Benorb Dec 17, 2017

Sombody has a real solution?
i want to do this: window.postMessage(document.cookie)
and im stuck with this error..
How can i solve it?

Benorb commented Dec 17, 2017

Sombody has a real solution?
i want to do this: window.postMessage(document.cookie)
and im stuck with this error..
How can i solve it?

@zecaptus

This comment has been minimized.

Show comment
Hide comment
@zecaptus

zecaptus Dec 18, 2017

You can probably solving this by ejecting your app from create-react-native-app and removing redscreen dependency. Btw I think this error shouldn't thrown in a production env.

zecaptus commented Dec 18, 2017

You can probably solving this by ejecting your app from create-react-native-app and removing redscreen dependency. Btw I think this error shouldn't thrown in a production env.

@rodrijuarez

This comment has been minimized.

Show comment
Hide comment
@rodrijuarez

rodrijuarez Dec 20, 2017

Also having the same problem in iOS, this problem isn't present in Android though. Hope this is fixed soon so we don't have to go through this kind of workarounds (that could cause some other problems)

rodrijuarez commented Dec 20, 2017

Also having the same problem in iOS, this problem isn't present in Android though. Hope this is fixed soon so we don't have to go through this kind of workarounds (that could cause some other problems)

@jeveloper

This comment has been minimized.

Show comment
Hide comment
@jeveloper

jeveloper Dec 21, 2017

@Benorb Hey, i've had the same issue. I read the source code and when running in dev mode , RN will throw an error but even if you dismiss and your webview will be operational, the app is messed up. Unfortunately you can test this by running in release mode and then you won't see the error. @zecaptus Sorry but your comment is incorrect. This is based on Macro code on Objective C that will invoke this, nothing to do with the web site itself.

jeveloper commented Dec 21, 2017

@Benorb Hey, i've had the same issue. I read the source code and when running in dev mode , RN will throw an error but even if you dismiss and your webview will be operational, the app is messed up. Unfortunately you can test this by running in release mode and then you won't see the error. @zecaptus Sorry but your comment is incorrect. This is based on Macro code on Objective C that will invoke this, nothing to do with the web site itself.

@rodrijuarez

This comment has been minimized.

Show comment
Hide comment
@rodrijuarez

rodrijuarez Jan 4, 2018

Is this by any chance solved in a newer version of react-native ? Or is this just laying out here for about half year?

rodrijuarez commented Jan 4, 2018

Is this by any chance solved in a newer version of react-native ? Or is this just laying out here for about half year?

@jeveloper

This comment has been minimized.

Show comment
Hide comment
@jeveloper

jeveloper Jan 4, 2018

@rodrijuarez Agreed to bring this up again. I wanted to say something but i am not entirely sure why in dev mode this is specifically throwing an error (maybe a warning would be enough) but maybe there is a reason. It's horrible for working on a solution and debugging.

jeveloper commented Jan 4, 2018

@rodrijuarez Agreed to bring this up again. I wanted to say something but i am not entirely sure why in dev mode this is specifically throwing an error (maybe a warning would be enough) but maybe there is a reason. It's horrible for working on a solution and debugging.

@Angelk90

This comment has been minimized.

Show comment
Hide comment
@Angelk90

Angelk90 Jan 6, 2018

You guys can publish your solutions, since days the solution I used is not working anymore, I do not understand the reason.

Angelk90 commented Jan 6, 2018

You guys can publish your solutions, since days the solution I used is not working anymore, I do not understand the reason.

@xxsnakerxx

This comment has been minimized.

Show comment
Hide comment
@xxsnakerxx

xxsnakerxx Jan 17, 2018

I found workaround that works for me (RN 0.52)

Just add at the end of the injectedScript

window.postMessage = window.originalPostMessage || window.postMessage;
const injectedScript = () => {
  window.postMessage(document.body.innerHTML);
  window.postMessage = window.originalPostMessage || window.postMessage;
}

<WebView
  source={source}
  injectedJavaScript={`(${String(injectedScript)})()`}
  onMessage={this._onMessage}
/>

xxsnakerxx commented Jan 17, 2018

I found workaround that works for me (RN 0.52)

Just add at the end of the injectedScript

window.postMessage = window.originalPostMessage || window.postMessage;
const injectedScript = () => {
  window.postMessage(document.body.innerHTML);
  window.postMessage = window.originalPostMessage || window.postMessage;
}

<WebView
  source={source}
  injectedJavaScript={`(${String(injectedScript)})()`}
  onMessage={this._onMessage}
/>
@Angelk90

This comment has been minimized.

Show comment
Hide comment
@Angelk90

Angelk90 Jan 17, 2018

@xxsnakerxx: Can I ask you if you could possibly make a working example of your code on Expo, in order to try it?

Angelk90 commented Jan 17, 2018

@xxsnakerxx: Can I ask you if you could possibly make a working example of your code on Expo, in order to try it?

@Angelk90

This comment has been minimized.

Show comment
Hide comment
@Angelk90

Angelk90 Jan 17, 2018

I use such a thing instead:

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

//*Reference
I do not understand why inside:
           whenRNPostMessageReady (function () {

I can put only one line, for example:
             postMessage (document.getElementById ( 'name'). innerHTML);
If I try to put more lines, example:

var c = document.getElementById ('name'). innerHTML;
  postMessage (c);

It stops working.

@xxsnakerxx :
Could you check if the same thing happens to you too?

Angelk90 commented Jan 17, 2018

I use such a thing instead:

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

//*Reference
I do not understand why inside:
           whenRNPostMessageReady (function () {

I can put only one line, for example:
             postMessage (document.getElementById ( 'name'). innerHTML);
If I try to put more lines, example:

var c = document.getElementById ('name'). innerHTML;
  postMessage (c);

It stops working.

@xxsnakerxx :
Could you check if the same thing happens to you too?

@tranduykhanh

This comment has been minimized.

Show comment
Hide comment
@tranduykhanh

tranduykhanh Mar 15, 2018

@MrLoh Confirm work on iOS! 👍

tranduykhanh commented Mar 15, 2018

@MrLoh Confirm work on iOS! 👍

@knod

This comment was marked as off-topic.

Show comment
Hide comment
@knod

knod Apr 9, 2018

@MrLoh: I know it's a bit rude to make this request here, but I've tried other avenues (searches, issues, discord, irc) and haven't been able to find a way to move forward. Would anyone be willing to come on to the irc channel (#reactnative) or discord and give me a few hints and tips? Maybe answer some questions? Same name there as on here. I don't think this is an appropriate place for a complex Q&A session, but my current code looks like this: https://pastebin.com/Epy9xSSn. I have a bouncer, so I'll get your message if you leave me one with my username in it. Let me know if you have a bouncer too or, if not, how else I can reach you/what time you'll be able to be on.

knod commented Apr 9, 2018

@MrLoh: I know it's a bit rude to make this request here, but I've tried other avenues (searches, issues, discord, irc) and haven't been able to find a way to move forward. Would anyone be willing to come on to the irc channel (#reactnative) or discord and give me a few hints and tips? Maybe answer some questions? Same name there as on here. I don't think this is an appropriate place for a complex Q&A session, but my current code looks like this: https://pastebin.com/Epy9xSSn. I have a bouncer, so I'll get your message if you leave me one with my username in it. Let me know if you have a bouncer too or, if not, how else I can reach you/what time you'll be able to be on.

ivank added a commit to ivank/react-native that referenced this issue Apr 16, 2018

Fix native postMessage test
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

ivank added a commit to ivank/react-native that referenced this issue Apr 16, 2018

Fix native postMessage test
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

ivank added a commit to ivank/react-native that referenced this issue Apr 16, 2018

Fix native postMessage test
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

@ivank ivank referenced a pull request that will close this issue Apr 16, 2018

Open

Fix native postMessage test #18879

ivank added a commit to ivank/react-native that referenced this issue May 19, 2018

Fix native postMessage test
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
@JulianKingman

This comment has been minimized.

Show comment
Hide comment
@JulianKingman

JulianKingman Jun 11, 2018

So I read through this whole thread, and several related ones and I don't see any solution that actually works reliably... This comment seemed promising: #10941 (comment) but it doesn't seem to matter what I do to define or redefine window.onMessage, I get the error a previous value was defined.

I'm just trying to get the window height, and pass it to react native to resize it. Here's my current script (that's failing):

const patchPostMessageJsCode = `
(function ready() {
  var body = document.body,
  html = document.documentElement;
  var height = Math.max(body.scrollHeight, body.offsetHeight, html.clientHeight, html.scrollHeight, html.offsetHeight);
  (function resetPostMessage () {
    if(window.originalPostMessage != undefined) {
      window.postMessage = window.originalPostMessage || window.postMessage;
    }
  })();
  function postWhenReady(message) {
    if (!window.postMessage) {
      resetPostMessage();
      setTimeout(postWhenReady(message), 200);
    }
    window.postMessage(message);
  }
  postWhenReady(JSON.stringify({height: height}));
  (function checkHeight () {
    height = Math.max(body.scrollHeight, body.offsetHeight, html.clientHeight, html.scrollHeight, html.offsetHeight);
    postWhenReady(JSON.stringify({height: height, interval: true}));
    setTimeout(checkHeight, 500);
  }))();
  resetPostMessage();
})();`;

If I skip the asynchronous stuff, it's fine. It seems like postMessage is getting set by the page I'm loading at some time after initial load, and react native has a difficult time coping with it, no matter how many times I "reset" window.postMessage. Is there a foolproof way to use postMessage?

JulianKingman commented Jun 11, 2018

So I read through this whole thread, and several related ones and I don't see any solution that actually works reliably... This comment seemed promising: #10941 (comment) but it doesn't seem to matter what I do to define or redefine window.onMessage, I get the error a previous value was defined.

I'm just trying to get the window height, and pass it to react native to resize it. Here's my current script (that's failing):

const patchPostMessageJsCode = `
(function ready() {
  var body = document.body,
  html = document.documentElement;
  var height = Math.max(body.scrollHeight, body.offsetHeight, html.clientHeight, html.scrollHeight, html.offsetHeight);
  (function resetPostMessage () {
    if(window.originalPostMessage != undefined) {
      window.postMessage = window.originalPostMessage || window.postMessage;
    }
  })();
  function postWhenReady(message) {
    if (!window.postMessage) {
      resetPostMessage();
      setTimeout(postWhenReady(message), 200);
    }
    window.postMessage(message);
  }
  postWhenReady(JSON.stringify({height: height}));
  (function checkHeight () {
    height = Math.max(body.scrollHeight, body.offsetHeight, html.clientHeight, html.scrollHeight, html.offsetHeight);
    postWhenReady(JSON.stringify({height: height, interval: true}));
    setTimeout(checkHeight, 500);
  }))();
  resetPostMessage();
})();`;

If I skip the asynchronous stuff, it's fine. It seems like postMessage is getting set by the page I'm loading at some time after initial load, and react native has a difficult time coping with it, no matter how many times I "reset" window.postMessage. Is there a foolproof way to use postMessage?

@jneuendorf

This comment has been minimized.

Show comment
Hide comment
@jneuendorf

jneuendorf Jun 18, 2018

Injecting a patched postMessage method did not work for me (RN 0.55, macOS 10.13, iOS). In my case the error only occurred when I rendered an iframe (React + ReactDOM) inside my WebView.

jneuendorf commented Jun 18, 2018

Injecting a patched postMessage method did not work for me (RN 0.55, macOS 10.13, iOS). In my case the error only occurred when I rendered an iframe (React + ReactDOM) inside my WebView.

ivank added a commit to ivank/react-native that referenced this issue Jun 19, 2018

Fix native postMessage test
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
@Dmitrylolo

This comment has been minimized.

Show comment
Hide comment
@Dmitrylolo

Dmitrylolo Jun 23, 2018

Injecting a patched postMessage method did not work for me. Error is showing even when i comment it in node_modules/react-native/React/Views/RCTWebView.m
"react": "16.3.0-alpha.1",
"react-native": "https://github.com/expo/react-native/archive/sdk-26.0.0.tar.gz"

Dmitrylolo commented Jun 23, 2018

Injecting a patched postMessage method did not work for me. Error is showing even when i comment it in node_modules/react-native/React/Views/RCTWebView.m
"react": "16.3.0-alpha.1",
"react-native": "https://github.com/expo/react-native/archive/sdk-26.0.0.tar.gz"

@Nachox07

This comment has been minimized.

Show comment
Hide comment
@Nachox07

Nachox07 Jun 27, 2018

Same issue with this versions:
"react": "16.3.2",
"react-native": "0.55.4",

Nachox07 commented Jun 27, 2018

Same issue with this versions:
"react": "16.3.2",
"react-native": "0.55.4",

@Lie8466

This comment has been minimized.

Show comment
Hide comment
@Lie8466

Lie8466 Jul 4, 2018

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

Then usewindow.RNPostMessag

Lie8466 commented Jul 4, 2018

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

Then usewindow.RNPostMessag

ivank added a commit to ivank/react-native that referenced this issue Jul 19, 2018

Fix native postMessage test
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

This comment has been minimized.

Show comment
Hide comment
@schlaegerz

schlaegerz 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.

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.

@stonecold123

This comment has been minimized.

Show comment
Hide comment
@stonecold123

stonecold123 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.

stonecold123 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

This comment has been minimized.

Show comment
Hide comment
@Titozzz

Titozzz Sep 9, 2018

Collaborator

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,

Collaborator

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,

@stonecold123

This comment has been minimized.

Show comment
Hide comment
@stonecold123

stonecold123 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.

stonecold123 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

This comment has been minimized.

Show comment
Hide comment
@Titozzz

Titozzz Sep 13, 2018

Collaborator

@stonecold123 please open an issue on the new repo

Collaborator

Titozzz commented Sep 13, 2018

@stonecold123 please open an issue on the new repo

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment