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

fix(android): messaging regression for multiple webviews #3394

Merged
merged 2 commits into from Apr 15, 2024

Conversation

Kudo
Copy link
Contributor

@Kudo Kudo commented Apr 10, 2024

Why

Fixes #3368 which is my regression from #3352

How

JSModule registerCallableModule() does not support multiple listeners. The newer WebView will overwrite the previously registered callbacks.
This PR tries to move registerCallableModule() at top as a module singleton. With an intermediate EventEmitter to dispatch events to each WebViews. I tries to import the internal vendored EventEmitter from react-native. If that is not ideal, we could replace as third-party EventEmitter such as fbemitter.

Test Plan

extend the Messsaging.tsx example as two WebViews and check whether messages are sent correctly.

import React, { Component } from 'react';
import { View, Alert, TextInput } from 'react-native';

import WebView from 'react-native-webview';

const HTML = `<!DOCTYPE html>\n
<html>
  <head>
    <title>Messaging</title>
    <meta http-equiv="content-type" content="text/html; charset=utf-8">
    <meta name="viewport" content="width=320, user-scalable=no">
    <style type="text/css">
      body {
        margin: 0;
        padding: 0;
        font: 62.5% arial, sans-serif;
        background: #ccc;
      }
    </style>
  </head>
  <body>
    <button onclick="sendPostMessage()">Send post message from JS to WebView</button>
    <p id="demo"></p>
    <p id="test">Nothing received yet</p>

    <script>
      function sendPostMessage() {
        window.ReactNativeWebView.postMessage('Message from JS');
      }

      window.addEventListener('message',function(event){
        document.getElementById('test').innerHTML = event.data;
        console.log("Message received from RN: ",event.data);
      },false);
      document.addEventListener('message',function(event){
        document.getElementById('test').innerHTML = event.data;
        console.log("Message received from RN: ",event.data);
      },false);

    </script>
  </body>
</html>`;

type Props = {};
type State = {};

export default class Messaging extends Component<Props, State> {
  state = {};

  constructor(props) {
    super(props);
    this.webView = React.createRef();
    this.webView2 = React.createRef();
  }

  render() {
    return (
      <View style={{ flex: 1, flexDirection: 'row' }}>
        <View style={{ flexDirection: 'column', flex: 1, margin: 4 }}>
          <TextInput
            style={{
              height: 40,
              borderColor: 'gray',
              borderWidth: 1,
              margin: 8,
            }}
            onSubmitEditing={(e) => {
              this.webView.current.postMessage(e.nativeEvent.text);
            }}
          />
          <WebView
            ref={this.webView}
            source={{ html: HTML }}
            onLoadEnd={() => {
              this.webView.current.postMessage('Hello from RN');
            }}
            automaticallyAdjustContentInsets={false}
            onMessage={(e: { nativeEvent: { data?: string } }) => {
              Alert.alert('Message received from JS: ', e.nativeEvent.data);
            }}
          />
        </View>

        <View style={{ flexDirection: 'column', flex: 1, margin: 4 }}>
          <TextInput
            style={{
              height: 40,
              borderColor: 'gray',
              borderWidth: 1,
              margin: 8,
            }}
            onSubmitEditing={(e) => {
              this.webView2.current.postMessage(e.nativeEvent.text);
            }}
          />
          <WebView
            ref={this.webView2}
            source={{
              html: HTML.replace(/from JS/g, 'from JS2'),
            }}
            onLoadEnd={() => {
              this.webView2.current.postMessage('Hello from RN2');
            }}
            automaticallyAdjustContentInsets={false}
            onMessage={(e: { nativeEvent: { data?: string } }) => {
              Alert.alert('Message received from JS2: ', e.nativeEvent.data);
            }}
          />
        </View>
      </View>
    );
  }
}

demo video:
Screen_recording_20240411_013607.webm

@TheAlmightyBob
Copy link
Collaborator

Could the "test plan" code actually be added as a new example in the example app?

@Kudo
Copy link
Contributor Author

Kudo commented Apr 11, 2024

Could the "test plan" code actually be added as a new example in the example app?

added as the MultiMessaging example

@TheAlmightyBob TheAlmightyBob merged commit 2379ad0 into react-native-webview:master Apr 15, 2024
11 checks passed
react-native-community-bot pushed a commit that referenced this pull request Apr 15, 2024
## [13.8.5](v13.8.4...v13.8.5) (2024-04-15)

### Bug Fixes

* **android:** messaging regression for multiple webviews ([#3394](#3394)) ([2379ad0](2379ad0))
@react-native-community-bot
Copy link
Collaborator

🎉 This PR is included in version 13.8.5 🎉

The release is available on:

Your semantic-release bot 📦🚀

@TheAlmightyBob
Copy link
Collaborator

Thanks for sorting this out @Kudo !

@Kudo Kudo deleted the @kudo/fix-3368 branch April 15, 2024 12:25
@Kudo
Copy link
Contributor Author

Kudo commented Apr 15, 2024

awesome! thanks @TheAlmightyBob for publishing the fix!

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

Successfully merging this pull request may close these issues.

Webview bridge maybe has some bug since v13.8.2
3 participants