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