Stripe.js 在 Android 上的 React Native WebView 中加载失败

问题描述 投票:0回答:1

问题概述: 我面临一个问题,即 Stripe.js 无法加载到我的 React Native 应用程序的 Android WebView 中,导致支付流程无法正常运行。该集成在 iOS 设备上完美运行,但在 Android 上,脚本无法加载。

设置: 我正在尝试在 WebView 中运行以下 HTML 来设置 Stripe 付款方式:

<!DOCTYPE html>
<html>
<head>
    <title>Stripe Setup Intent</title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script src="https://js.stripe.com/v3/"></script>
    <style>
        body {
            margin: 0;
            padding: 0;
            font-family: Arial, sans-serif;
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100vh;
            background-color: #f5f5f5;
        }
        .container {
            width: 100%;
            max-width: 500px;
            padding: 20px;
            background: white;
            box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
            border-radius: 8px;
            text-align: center;
            overflow-y: auto;
        }
        h2 { margin-bottom: 20px; }
        p { margin-bottom: 40px; }
        .spinner {
            display: inline-block;
            width: 50px;
            height: 50px;
            border: 3px solid rgba(195, 195, 195, 0.6);
            border-radius: 50%;
            border-top-color: #636767;
            animation: spin 1s ease-in-out infinite;
        }
        @keyframes spin { to { transform: rotate(360deg); } }
    </style>
</head>
<body>
    <div class="container" role="alert">
        <h2>Let's setup your payment method</h2>
        <p id="status-message">Connecting to Stripe...</p>
        <div class="spinner" aria-hidden="true"></div>
    </div>
    <script>
        document.addEventListener("DOMContentLoaded", function() {
            const stripe = Stripe('<%= stripePublishableKey %>');
            const clientSecret = '<%= clientSecret %>';
            stripe.confirmAcssDebitSetup(clientSecret, {
                payment_method: {
                    billing_details: {
                        name: '<%= user.fullName %>',
                        email: '<%= user.email %>',
                    },
                },
            }).then(function(result) {
                if (result.error) {
                    document.querySelector('.container').innerHTML = \`
                        <p>There was an error setting up your payment method. Please try again.</p>
                        <p>If the problem persists, please visit the "Contact Us" screen in the app or email us at <a href="mailto:[email protected]">[email protected]</a>.</p>
                    \`;
                } else {
                    document.querySelector('.container').innerHTML = \`
                        <p>Your payment method has been successfully set up!</p>
                        <p>You will be redirected shortly.</p>\`;
                }
            });
        });

        window.addEventListener('resize', function() {
            if (document.activeElement.tagName === 'INPUT' || document.activeElement.tagName === 'TEXTAREA') {
                document.activeElement.scrollIntoView({ behavior: 'smooth' });
            }
        });
    </script>
</body>
</html>

React Native 中的 webview(在 iOS 上工作得很好):

import { View } from 'react-native';
import React from 'react';
import StripeTos from '@Components/StripeTos';
import BackIcon from '@Components/BackIcon';
import { WebView } from 'react-native-webview';
import { styles } from './styles';
import { height, width } from '@Utils/dimensions';

interface Props {
  isVisible: boolean;
  close: () => void;
  htmlStr: string;
}
const StripeWebview = ({ isVisible = false, close, htmlStr = '' }: Props) => {
  return (
    <View>
      <StripeTos
        close={close}
        onSubmit={() => {}}
        open={isVisible}
        isWebView
        isSwipable={false}
        avoidKeyboard={false}
        containerStyle={{
          width: width(100),
          height: height(90),
          borderWidth: 0,
          backgroundColor: 'white',
        }}>
        <View style={styles.container}>
          <View style={styles.backBtn}>
            <BackIcon onPress={close} />
          </View>
          {isVisible && (
          <WebView
            source={{ html: htmlStr }}
            style={{
              flex: 1,
            }}
            scalesPageToFit={true}
            javaScriptEnabled={true}
            domStorageEnabled={true}
            mixedContentMode="always"
            onMessage={event => {
              console.log(event.nativeEvent.data);
            }}
            onError={syntheticEvent => {
              const { nativeEvent } = syntheticEvent;
              console.warn('WebView error: ', nativeEvent);
            }}
            onHttpError={syntheticEvent => {
              const { nativeEvent } = syntheticEvent;
              console.warn('WebView HTTP error: ', nativeEvent);
            }}
          />
          )} 
        </View>
      </StripeTos>
    </View>
  );
};

export default StripeWebview;

问题: Stripe.js 脚本无法在 Android WebView 中专门加载。相反,我只看到“正在连接到 Stripe...”和旋转器,基本上是以下部分(即使等待一个小时后):

<div class="container" role="alert">
    <h2>Let's setup your payment method</h2>
    <p id="status-message">Connecting to Stripe...</p>
    <div class="spinner" aria-hidden="true"></div>
</div>

相同的设置在使用 WebView 的 iOS 设备上运行得非常好。

我注意到这是 stripe.js 脚本加载部分卡住的地方,所以我测试了其他几个脚本,看看它是否可以加载它们。看起来它可以在 Android WebView 中很好地加载 jQuery 脚本,但 Lodash 似乎也无法加载。

我尝试过的: 用户代理测试:我尝试更改 userAgent 以模拟 iOS Safari 浏览器和其他现代浏览器,但问题仍然存在。

外部脚本测试: jQuery 在 Android WebView 中加载没有问题。 Lodash 和 Stripe.js 加载失败,说明可能与 WebView 中处理特定脚本的方式有关。

WebView配置:我已确保WebView设置正确配置,包括: javaScriptEnabled:true domStorageEnabled:true 混合内容模式:“始终”

Promises 和 TLS 1.2:Stripe.js 需要两者,并且设备都支持。

android react-native stripe-payments android-webview react-native-webview
1个回答
0
投票

enter image description here我尝试通过加载不同的 Stripe.js 页面来重现 React Native WebView 上的问题,它对我来说效果很好:https://4242.io/ payment-element

问题很可能出在您的 HTML 代码中。如果问题仍然存在,我建议您联系 Stripe 支持人员了解该问题以及他们可以用来重现问题的示例应用程序 - https://support.stripe.com/?contact=true

© www.soinside.com 2019 - 2024. All rights reserved.