react-native-webview-messaging icon indicating copy to clipboard operation
react-native-webview-messaging copied to clipboard

Setting onMessage on a WebView overrides existing values of window.postMessage

Open SamBellerose opened this issue 7 years ago • 9 comments

I've got this error on iOS when running the project, working well on Android

I tried adding this to my WebView it removed the error, but the events were not being called after injectedJavaScript="window.postMessage = String(Object.hasOwnProperty).replace('hasOwnProperty', 'postMessage');"

Bug reference: https://github.com/facebook/react-native/issues/10865

SamBellerose avatar Nov 08 '17 18:11 SamBellerose

@SamBellerose Could you please provide code sample you're getting this error with?

lesnitsky avatar Nov 08 '17 19:11 lesnitsky

Hi,

I'm experiencing a similar issue. Did anyone find a solution?

Moses

mosesmc52 avatar Nov 17 '17 20:11 mosesmc52

@SamBellerose, @mosesmc52 could you please provide more details? I will be really great to assist you

lesnitsky avatar Nov 17 '17 22:11 lesnitsky

@R1ZZU, user @PaddyLock is using my react-native-webview-braintree package and has run into the same error on iOS (no problems in in Android). I'm sure it's the same problem that @SamBellerose and @mosesmc52 .

It also looks like the issue is being referenced in the react-native issue thread here https://github.com/facebook/react-native/issues/10865.

Here is the code from my package that experiences the issue.

export default class BraintreePaymentWebview extends React.Component {
  constructor() {
    super();

    this.state = {
      paymentAPIResponse: null,
      showGetNonceActivityIndicator: false,
      showSubmitPaymentActivityIndicator: false
    };
  }
  componentDidMount() {
    // register listeners to listen for events from the html
    // we'll receive a nonce once the requestPaymentMethodComplete is completed
    this.registerMessageListeners();
    console.log('wbvw braintree mounted');
  }

  registerMessageListeners = () => {
    const { messagesChannel } = this.webview;

    messagesChannel.on('RETRIEVE_NONCE_PENDING', event => {
      this.setState({ showGetNonceActivityIndicator: true });
      console.log('RETRIEVE_NONCE_PENDING');
    });

    messagesChannel.on('RETRIEVE_NONCE_FULFILLED', event => {
      console.log('RETRIEVE_NONCE_FULFILLED');
      this.setState({ showGetNonceActivityIndicator: false });
      this.setState({ showSubmitPaymentActivityIndicator: true });
      this.props.nonceObtainedCallback(event.payload.response.nonce);
    });

    messagesChannel.on('RETRIEVE_NONCE_REJECTED', event => {
      console.log('RETRIEVE_NONCE_REJECTED');
      this.setState({ showGetNonceActivityIndicator: false });
    });

    messagesChannel.on('GO_BACK', () => {
      this.props.navigationBackCallback();
    });
  };

  // send the client token to HTML file to begin the braintree flow
  // called when the HTML in the webview is loaded
  sendClientTokenToHTML = () => {
    this.webview.emit('TOKEN_RECEIVED', {
      payload: {
        clientToken: this.props.clientToken,
        options: this.props.options
      }
    });
  };

  // handle purchase responses that parent component sends after making purchase API call
  handlePurchaseResponse = response => {
    console.log('handlePurchaseResponse');
    if (response === 'PAYMENT_SUCCESS') {
      console.log('emitting purchaseSuccess');
      this.setState({ showSubmitPaymentActivityIndicator: false });
      this.webview.emit('PURCHASE_FULFILLED');
    } else {
      this.setState({ showSubmitPaymentActivityIndicator: false });
      this.webview.emit('PURCHASE_REJECTED');
    }
  };

  componentWillReceiveProps = nextProps => {
    console.log({ nextProps });
    if (nextProps.paymentAPIResponse !== this.state.paymentAPIResponse) {
      console.log(nextProps.paymentAPIResponse);
      this.setState({ paymentAPIResponse: nextProps.paymentAPIResponse });
      this.handlePurchaseResponse(nextProps.paymentAPIResponse);
    }
  };

  render() {
    return (
      <View
        style={{
          flex: 1,
          backgroundColor: 'green'
        }}
      >
        <View
          style={{
            flex: 1,
            backgroundColor: 'blue'
          }}
        >
          <WebView
            onLoad={this.sendClientTokenToHTML}
            source={require('./dist/index.html')}
            style={{ flex: 1 }}
            ref={component => (this.webview = component)}
          />
        </View>
        {renderIf(this.state.showGetNonceActivityIndicator)(
          <View style={styles.activityOverlayStyle}>
            <View style={styles.activityIndicatorContainer}>
              <ActivityIndicator
                size="large"
                animating={this.state.showGetNonceActivityIndicator}
                color="blue"
              />
            </View>
          </View>
        )}
        {renderIf(this.state.showSubmitPaymentActivityIndicator)(
          <View style={styles.activityOverlayStyle}>
            <View style={styles.activityIndicatorContainer}>
              <ActivityIndicator
                size="large"
                animating={this.state.showSubmitPaymentActivityIndicator}
                color="green"
              />
            </View>
          </View>
        )}
      </View>
    );
  }
}

BraintreePaymentWebview.propTypes = {
  options: PropTypes.object,
  clientToken: PropTypes.string.isRequired,
  paymentAPIResponse: PropTypes.string.isRequired,
  nonceObtainedCallback: PropTypes.func.isRequired,
  navigationBackCallback: PropTypes.func
};

I'll try to do some more investigating to figure out what specific portion of my code initiates the problem.

reggie3 avatar Jan 05 '18 15:01 reggie3

@reggie3 I will investigate this issue and try to provide appropriate workaround

lesnitsky avatar Jan 05 '18 15:01 lesnitsky

Thanks. Let me know if I can help.

reggie3 avatar Jan 05 '18 15:01 reggie3

Also running into this issue - very interested in a resolution.

Maximell avatar Jan 10 '18 04:01 Maximell

Same issue

lBroth avatar Feb 17 '18 08:02 lBroth

I did a PR for this in #22 , it solved it for me, and it relies on a fix suggested in https://github.com/facebook/react-native/issues/10865. I don't know if this breaks other stuff though. @R1ZZU @reggie3 @Maximell @lBroth can you test to check if it works for you as well and it is not breaking anything?

nacho-carnicero avatar Feb 21 '18 15:02 nacho-carnicero