Flutter WebView集成Stripe Checkout安卓报错:需设置allow-same-origin
问题原因分析
- 安卓WebView对data:URL的沙箱限制:data:协议加载的HTML默认处于无同源的沙箱环境,且Cookie被强制禁用,而Stripe.js运行需要同源权限(
allow-same-origin)和Cookie支持,直接触发了"Stripe.js requires 'allow-same-origin' if sandboxed"及Cookie读取失败的错误。 - Content-Security-Policy设置无效:在
loadRequest的headers中设置CSP对data:URL无效,因为data协议的资源不遵循常规HTTP头部规则。 - 安卓WebView未启用Payment特性:
"Unrecognized feature: 'payment'"报错说明安卓WebView默认未开启Payment API支持,影响Stripe脚本初始化。
解决方案
方案一:改用本地Asset文件加载HTML(推荐)
将HTML内容保存为本地Asset文件,通过asset协议加载,让WebView赋予其正常的同源环境,绕过data:URL的沙箱限制。
步骤1:配置Asset文件
- 在项目根目录创建
assets文件夹,新建stripe_checkout.html文件,内容如下:
<!DOCTYPE html> <html> <script src="https://js.stripe.com/v3/"></script> <style> body, html { width: 100%; height: 100%; margin: 0; padding: 0; } #loader { width: 100%; height: 100%; display: flex; justify-content: center; align-items: center; } </style> <head><title>Stripe checkout</title></head> <body> <div id="loader"> <span>Please wait...</span> </div> </body> </html>
- 在
pubspec.yaml中添加Asset引用:
flutter: assets: - assets/stripe_checkout.html
步骤2:修改Flutter代码
更新CheckoutPage的initialUrl和WebViewController配置:
class _CheckoutPageState extends State<CheckoutPage> { late WebViewController _controller; @override void initState() { super.initState(); _controller = WebViewController() ..clearCache() ..setJavaScriptMode(JavaScriptMode.unrestricted) // 安卓端启用必要设置 ..androidSettings = const AndroidWebSettings( domStorageEnabled: true, javaScriptCanOpenWindowsAutomatically: true, allowContentAccess: true, allowFileAccess: true, databaseEnabled: true, ) ..setNavigationDelegate(NavigationDelegate( onNavigationRequest: (NavigationRequest request) { if (request.url.startsWith(checkoutSuccessUrl)) { context.pop('success'); } else if (request.url.startsWith(checkoutFailureUrl)) { context.pop('cancel'); } return NavigationDecision.navigate; }, onPageFinished: (String url) { if (url.startsWith('asset:///assets/stripe_checkout.html')) { _redirectToStripe(); } }, onWebResourceError: (error) { print(error); }, )) ..loadRequest(Uri.parse(initialUrl)); } // 修改为Asset路径 String get initialUrl => 'asset:///assets/stripe_checkout.html'; void _redirectToStripe() { final redirectToCheckoutJs = ''' var stripe = Stripe('$stripePublicKey'); stripe.redirectToCheckout({ sessionId: '${widget.sessionId}' }).then(function (result) { if (result.error) { console.error(result.error.message); } }); '''; _controller.runJavaScript(redirectToCheckoutJs); } // 其余代码保持不变 }
方案二:调整安卓WebView沙箱与Cookie设置(备选)
如果必须使用data:URL,需通过安卓原生配置解除沙箱限制并启用Cookie:
步骤1:启用Cookie支持
在initState中添加Cookie初始化代码:
import 'package:webview_flutter/webview_flutter.dart'; import 'dart:io'; @override void initState() { super.initState(); // 安卓端启用Cookie if (Platform.isAndroid) { final cookieManager = CookieManager(); cookieManager.setCookie( url: 'https://js.stripe.com', name: 'stripe_session', value: '', domain: 'js.stripe.com', path: '/', expires: DateTime.now().add(const Duration(days: 365)), isSecure: true, ); } // 其余WebViewController初始化代码... }
步骤2:修改WebView沙箱设置
通过安卓原生WebSettings解除沙箱限制:
_controller.androidSettings = AndroidWebSettings( allowContentAccess: true, allowFileAccess: true, allowUniversalAccessFromFileURLs: true, domStorageEnabled: true, javaScriptCanOpenWindowsAutomatically: true, setSupportMultipleWindows: true, );
关键注意事项
- iOS对data:URL的沙箱限制更宽松,因此无此问题,但安卓需严格遵循同源策略。
- 务必确保
stripePublicKey和sessionId正确无误,避免因参数错误导致跳转失败。 - 测试时启用WebView调试(
AndroidWebViewController.enableDebugging(true)),方便查看控制台日志定位问题。
内容的提问来源于stack exchange,提问作者Tanjim ahmed
相关产品推荐
相关产品推荐

