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

Android window.ReactNativeWebView.postMessage issue #323

Closed
RobinUS2 opened this issue Feb 7, 2019 · 24 comments
Closed

Android window.ReactNativeWebView.postMessage issue #323

RobinUS2 opened this issue Feb 7, 2019 · 24 comments

Comments

@RobinUS2
Copy link

RobinUS2 commented Feb 7, 2019

Hi there,

We implemented version 5.0.5 of the library with #243 incorporated into it using window.ReactNativeWebView.postMessage for bidirectional communication. We use both iOS and Android with "react-native": "0.57.0".

The problem we see is the following:
iOS => web view => ✅ (use injectJavaScript to send a message)
web view => iOS => ✅ (use window.ReactNativeWebView.postMessage to send a message)
Android => web view => ✅ (use injectJavaScript to send a message)
web view => Android => 👎 (use window.ReactNativeWebView.postMessage to send a message)

Android errors with:

java bridge method can't be invoked on a non injected object.

This feels somewhat weird, since the whole java bridge is supposed to be managed for us, as long as messagingEnabled=true, which is computed from messagingEnabled={typeof this.props.onMessage === 'function'}. Our WebView has onMessage implemented with a function, so that all should be good, and is also "confirmed" by the fact that iOS works as expected.

Am I missing something obvious, or is this a bug?

Thanks in advance!

@Titozzz
Copy link
Collaborator

Titozzz commented Feb 7, 2019

Can you dig more? Same scenario is working fine on my own app :)

@RobinUS2
Copy link
Author

RobinUS2 commented Feb 7, 2019

Been digging a lot. We've found that a downgrade to 4.1.0 works.

Are there known issues with certain Android versions maybe?

@Titozzz
Copy link
Collaborator

Titozzz commented Feb 7, 2019

Not that I'm aware of 🤔 . Did you rebuild the native side of the app after upgrade?

@tapir
Copy link

tapir commented Feb 11, 2019

It's window.ReactNativeWebview.postMessage not window.ReactNativeWebView.postMessage
Edit: Wait did they change it again!?? is it Webview or WebView. This is becoming ridiculous at this point

@Titozzz
Copy link
Collaborator

Titozzz commented Feb 11, 2019

@tapir see #324 (comment)

@RobinUS2
Copy link
Author

The reference is correct, it also works on iOS but not in Android. We rebuilt de app multiple times from scratch removing all intermediate files, still no succes. The downgrade does work to 4.1.0 but that's kind a odd as you say that the latest should work as well.

@Titozzz
Copy link
Collaborator

Titozzz commented Feb 12, 2019

@RobinUS2 I'm using latest in production, so it is working. There must be something we are missing here.

@RobinUS2
Copy link
Author

@Titozzz I agree, it must be something very subtle. Could you share a skeleton project or something where you implement this so we can review line by line, character (and case 😉 ) to see what's going on?

@notlose
Copy link

notlose commented Feb 14, 2019

same here, android lollipop 5.0.2

@Titozzz
Copy link
Collaborator

Titozzz commented Feb 14, 2019

@RobinUS2 Can you instead submit a small reproduction of the bug?

@notlose
Copy link

notlose commented Feb 14, 2019

Sorry, my faults, upgraded from 2.x. missed the breaking change note in 5.0

@laukaichung
Copy link

laukaichung commented Feb 21, 2019

My RN webview needs to communicate to a remote page of my website that uses ReactJS.

On the webpage, I see that the window.ReactNativeWebView exists, but the postMessage() method doesn't exist under it. I have to use

  // used in componentDidMount
  window.postMessage = function(data) {
    window.ReactNativeWebView.postMessage(data);
  };

as indicated in the release notes to get it working.Is it a bug? I find it odd that the postMessage() method doesn't exist when the Webview communicates to a remote web page?

@Titozzz
Copy link
Collaborator

Titozzz commented Feb 21, 2019

because overriding an existing postMessage function was a bad practice, and instead we decided to scope it inside an object. Since you have control over your react app directly I would advise against doing that and calling window.ReactNativeWebView.postMessage(data); directly

@laukaichung
Copy link

laukaichung commented Feb 21, 2019

@Titozzz
Yes, but the odd thing is that window.ReactNativeWebView exists, but it is just the method postMessage() doesn't exist. I will test it more to figure it out.

@Titozzz
Copy link
Collaborator

Titozzz commented Feb 21, 2019

please test more because the method does exist 😄

@laukaichung
Copy link

@Titozzz
I didn't realize that the targetOrigin argument must be omitted in window.ReactNativeWebView.postMessage().

If the targetOrigin(*) is added, it will throw the method does not exist error!

// This one won't work.
window.ReactNativeWebView.postMessage(JSON.stringify(data), "*");

// This will work.
window.ReactNativeWebView.postMessage(JSON.stringify(data));

@Titozzz
Copy link
Collaborator

Titozzz commented Feb 21, 2019

Yeah, this is the second reason we moved it actually because using '*' was a security issue 👍

@victor-ca
Copy link

#363
hello, for this to work now it looks like it has to be smth like this

/*ios*/
/*>*/window/*<*/.addEventListener('message', this.messageReceived);

/*droid*/
/*>*/document/*<*/.addEventListener('message', this.messageReceived);

however it looks like disparity is not intentional and will be ironed out.

to push it furtherer since we have a separate bridge to communicate to sent messages RN why not re-use it to send events down to WebView too... smth like

ReactNativeWebView.onMessage(this.messageReceived)

maybe it would also make sense to use a different name for postMessage to avoid confusion related to browser's postMessage signature?

ReactNativeWebView.sendMessage(m)

@RobinUS2, @Titozzz, @jamonholmgren, what do you guys think? any opinion/thoughts on this?

@CrazyOldDoctor
Copy link

@Titozzz
I didn't realize that the targetOrigin argument must be omitted in window.ReactNativeWebView.postMessage().

If the targetOrigin(*) is added, it will throw the method does not exist error!

// This one won't work.
window.ReactNativeWebView.postMessage(JSON.stringify(data), "*");

// This will work.
window.ReactNativeWebView.postMessage(JSON.stringify(data));

Thanks! It works really well.

@Titozzz
Copy link
Collaborator

Titozzz commented Feb 28, 2019

@victor-ca webview.postMessage is not documented and I would advise against using it, I personally use injectJavascript, it allows better flexibility. See here for a demo of what you could do #66 (comment)

@guavadevelopment
Copy link

I just had the same error and narrowed it down in my case to a javascript binding issue. You can easily reproduce the java bridge method can't be invoked on a non injected object error by assigning the window.ReactNativeWebView.postMessage to a local variable then trying to invoke that:

let postMessageProxy = window.ReactNativeWebView.postMessage;
postMessageProxy('hey....') //boom :(

By assigning to a local variable and calling that, javascript is changing the functions this and the Android WebView appears to be quite unhappy with that. It is quite easy to work around by ensuring the binding is preserved:

let postMessageProxy = function(data) { window.ReactNativeWebView.postMessage(data); }
postMessageProxy('hey....') //yay :)

As a real world example and the reason I came across this was for some code which was shared between hosting in a WebView or an iframe and I was trying to do this:

//find a postMessage to talk to hoster
let postMessage = window.parent.postMessage;
if(window.ReactNativeWebView) {
    postMessage = window.ReactNativeWebView.postMessage;
}

postMessage('hey');

@Hirurgo
Copy link

Hirurgo commented Aug 15, 2019

"react-native": "0.58.6"

still reproduce on Android 7 and lower

@Liqiankun
Copy link

@guavadevelopment You saved my ass!
I don't know why it works, but it does.

@fimak
Copy link

fimak commented Oct 11, 2023

@Titozzz I didn't realize that the targetOrigin argument must be omitted in window.ReactNativeWebView.postMessage().

If the targetOrigin(*) is added, it will throw the method does not exist error!

// This one won't work.
window.ReactNativeWebView.postMessage(JSON.stringify(data), "*");

// This will work.
window.ReactNativeWebView.postMessage(JSON.stringify(data));

Thanks bro

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests