We are using react-nattive-webview to display Google Pay button. We are using instructions: Embedded checkout - Payment API reference . When the button is clicked, OR_BIBED_15 error is raised.
import { NativeStackScreenProps } from "@react-navigation/native-stack";
import React, { useRef, useState } from "react";
import { Linking, StyleSheet, View } from "react-native";
import { Text } from "react-native-paper";
import WebView from "react-native-webview";
import i18n from "src/config/language";
import { Store, useStore } from "src/store/store";
import Screen from "../atoms/Screen";
interface PaymentWebViewParams {
paymentUrl?: string;
amount?: number;
onPaymentSuccess?: () => void;
onPaymentError?: () => void;
}
const Options = {
options: {
methods: ["card"],
methods_disabled: [],
card_icons: ["mastercard", "visa"],
fields: false,
full_screen: false,
button: true,
hide_title: true,
hide_link: true,
email: false,
theme: {
type: "light",
preset: "reset",
},
},
params: {
merchant_id: 1549901,
required_rectoken: "y",
currency: "GEL",
amount: 500,
},
css_variable: {
main: "#7d8ff8",
card_bg: "#353535",
card_shadow: "#9ADBE8",
},
};
const html = `
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Payment</title>
<link rel="stylesheet" href="https://pay.fondy.eu/latest/checkout-vue/checkout.css">
<style>
html, body {
height: 100%;
margin: 0;
padding: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
}
#checkout-container {
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
padding: 16px;
box-sizing: border-box;
}
</style>
</head>
<body>
<div id="checkout-container"></div>
<script src="https://pay.flitt.com/latest/checkout-vue/checkout.js"></script>
<script>
// Payment configuration
const Options = ${JSON.stringify(Options)};
// Initialize checkout when DOM is ready
document.addEventListener('DOMContentLoaded', function() {
if (typeof checkout === 'function') {
checkout("#checkout-container", Options);
} else {
console.error('Checkout function not available');
}
});
// Handle payment success/error callbacks
window.addEventListener('message', function(event) {
if (event.data.type === 'payment_success') {
window.ReactNativeWebView && window.ReactNativeWebView.postMessage(JSON.stringify({
type: 'payment_success',
data: event.data
}));
} else if (event.data.type === 'payment_error') {
window.ReactNativeWebView && window.ReactNativeWebView.postMessage(JSON.stringify({
type: 'payment_error',
data: event.data
}));
}
});
</script>
</body>
</html>
`;
export default function PaymentWebView({
navigation,
route,
}: NativeStackScreenProps<any, "PaymentWebView">) {
const { amount, onPaymentSuccess, onPaymentError } =
route.params as PaymentWebViewParams & { amount?: number };
const { setError, setMessage } = useStore((state: Store) => state);
const webViewRef = useRef(null);
const [loading, setLoading] = useState(true);
// Generate dynamic HTML with the payment amount
const generateHTML = () => {
return html.replace("amount: 500", `amount: ${amount || 500}`);
};
const handleLoadStart = () => {
setLoading(true);
};
const handleLoadEnd = () => {
setLoading(false);
};
const handleError = (syntheticEvent: any) => {
const { nativeEvent } = syntheticEvent;
console.warn("WebView error: ", nativeEvent);
setError(i18n.t("purchaseError"));
navigation.goBack();
};
return (
<Screen style={styles.container}>
<View style={styles.webviewContainer}>
<WebView
ref={webViewRef}
// source={{ uri: "https://codepen.io/flitt/pen/BaggpVw" }}
source={{ html: generateHTML(), baseUrl: "https://google.com" }}
style={styles.webview}
onLoadStart={handleLoadStart}
onLoadEnd={handleLoadEnd}
onError={handleError}
// onMessage={handleMessage}
javaScriptEnabled={true}
domStorageEnabled={true}
startInLoadingState={true}
scalesPageToFit={true}
sharedCookiesEnabled
thirdPartyCookiesEnabled
allowsBackForwardNavigationGestures={true}
injectedJavaScript={`(function() {
const open = window.open;
window.open = function(url) {
window.ReactNativeWebView.postMessage(JSON.stringify({ t:'OPEN', url }));
return null;
};
document.addEventListener('click', function(e){
const a = e.target.closest('a[target="_blank"]');
if (a && a.href) { e.preventDefault();
window.ReactNativeWebView.postMessage(JSON.stringify({ t:'OPEN', url:a.href }));
}
}, true);
})();
true;`}
setSupportMultipleWindows
onCreateWindow={(e) => {
Linking.openURL(e.nativeEvent.targetUrl);
return false;
}}
onMessage={(e) => {
try {
const m = JSON.parse(e.nativeEvent.data);
if (m.t === "OPEN" && m.url) Linking.openURL(m.url);
} catch {}
}}
/>
</View>
{loading && (
<View style={styles.loadingContainer}>
<Text style={styles.loadingText}>{i18n.t("loading")}</Text>
</View>
)}
</Screen>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
header: {
padding: 16,
borderBottomWidth: 1,
borderBottomColor: "#E5E5E5",
backgroundColor: "#FFFFFF",
},
headerText: {
fontSize: 18,
fontWeight: "600",
color: "#20232B",
textAlign: "center",
},
webviewContainer: {
flex: 1,
},
webview: {
flex: 1,
},
loadingContainer: {
position: "absolute",
top: 0,
left: 0,
right: 0,
bottom: 0,
justifyContent: "center",
alignItems: "center",
backgroundColor: "rgba(255, 255, 255, 0.8)",
},
loadingText: {
fontSize: 16,
color: "#636B74",
},
});