Inconsistent Javascript in WebView

I have a bizarre bug to figure out using from within a WebView (imported from react-native-webview

I am running on Expo version 33.0.4

We have a Stripe checkout using Stripe Elements. To do this, we are building the HTML/JS on the fly within a WebView. We manage different environments using expo-env.

Our code is performing exactly as expected in dev, but as soon as i switch to prod or staging, the JS seems to fail to run - only in Android. This leads me to believe there could be something strange happening in the WebView itself, but i cannot think what.

The code looks a little like this;

import React from 'react'
import PropTypes from 'prop-types'
import { WebView } from 'react-native-webview'
import { envConfig } from 'config'
import { colors } from 'theme'

import { style } from './constants'

const StripeElementsCardDetailsForm = ({
  onLoad,
  submitButtonText,
  cancelButtonText,
  onFormSubmit,
  onMessage,
}) => {
  const jsCode = `(function() {
    // This applies a fix for react-native-webview in Expo; https://github.com/expo/expo/issues/4463
    if (!window.ReactNativeWebView) {
      window.ReactNativeWebView = window['ReactABI33_0_0NativeWebView'];
    }
  })();`

  return (
    <WebView
      javaScriptEnabled
      scrollEnabled={false}
      bounces={false}
      injectedJavaScript={jsCode}
      originWhitelist={['*']}
      source={{
        html: `
          <head>
            <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0">
            <link href="https://fonts.googleapis.com/css?family=Rubik:400,500&display=swap" rel="stylesheet">
            ${style}
          </head>
          <body>
            <script src="https://js.stripe.com/v3/"></script>
            <form action="/charge" method="post" id="payment-form">
              <div class="form-row">
                <label for="card-element">
                  Credit or debit card
                  <div id="card-number-element" class="input">
                  </div>
                </label>

                <div class="row">
                  <div class="half-left">
                    <label for="card-expiry">
                      Expiry
                    </label>
                    <div id="card-expiry" class="input">
                    </div>
                  </div>

                  <div class="half-right">
                    <label for="card-cvc">
                      CVC
                    </label>
                    <div id="card-cvc" class="input">
                    </div>
                  </div>
                </div>
              </div>

              <button id="submit-button" class="submit">
                <div id="loader"></div>
                ${submitButtonText}
              </button>
            </form>

            <button id="cancel" class="cancel">${cancelButtonText}</button>

            <script>
              var stripe = Stripe('${envConfig.STRIPEKEY}');

              var cardNumber = elements.create('cardNumber', {style: elementStyles, classes: elementClasses});
              cardNumber.mount('#card-number-element');

              var cardExpiry = elements.create('cardExpiry', {style: elementStyles, classes: elementClasses});
              cardExpiry.mount('#card-expiry');

              var cardCvc = elements.create('cardCvc', {style: elementStyles, classes: elementClasses, placeholder: '123'});
              cardCvc.mount('#card-cvc');

              var form = document.getElementById('payment-form');

              form.addEventListener('submit', function(event) {
                 // Do something with the form...
                 event.preventDetault();
              });

              var cancelButton = document.getElementById('cancel');

              cancelButton.addEventListener('click', function() {
                window.ReactNativeWebView.postMessage(JSON.stringify({ cancel: true }));
              })
            </script>
          </body>
        `,
        baseUrl: '',
      }}
      onMessage={onMessage}
      onLoad={() => onLoad()}
      useWebKit
    />
  )
}

StripeElementsCardDetailsForm.propTypes = {
  onLoad: PropTypes.func.isRequired,
  submitButtonText: PropTypes.string.isRequired,
  cancelButtonText: PropTypes.string.isRequired,
  onFormSubmit: PropTypes.string.isRequired,
  onMessage: PropTypes.func.isRequired,
}

export default StripeElementsCardDetailsForm

You can see that there is a fix in there for the postMessage stuff. The ONLY parameter to change through different environments is the STRIPEKEY. And the issue ONLY effects Android.

We even have this running in a Web version (slightly different setup, same Stripe keys) and it works all through the different environments.

This could always be a red-herring and RNWV could be working as expected, but i have to start somewhere.

If anyone knows of any Android qwereks, i’m all ears

Turns out i needed to add a baseUrl… not completely sure why… :man_shrugging:

1 Like

This topic was automatically closed 15 days after the last reply. New replies are no longer allowed.