Flutter WebView Issue with Stripe Checkout: "Stripe.js requires 'allow-same-origin' if sandboxed."

92 views Asked by At

I'm encountering an error while attempting to open Stripe Checkout in a Flutter webview on android, specifically: "Stripe.js requires 'allow-same-origin' if sandboxed." Here's a breakdown of the situation:

In my Flutter app, I've integrated Stripe payments using webview_flutter to enable the Stripe Checkout session since it's designed for web apps. The checkout page is constructed using HTML and is loaded into a WebView. The HTML contains the necessary Stripe script and styling.

The Flutter code for the checkout page is structured with a stateful widget, including the necessary initialization for the WebView and handling navigation events. However, upon opening the page, it remains stuck on the initial URL and doesn't proceed to open the Stripe Checkout. Also this problem is happening only in andoid, on iOS everything is fine. When I run it on android the console displays three distinct issues:

I/chromium( 7353): [INFO:CONSOLE(1)] "Unrecognized feature: 'payment'.", source: https://js.stripe.com/v3/ (1)
"Unrecognized feature: 'payment'."
"Stripe.js requires 'allow-same-origin' if sandboxed."
"Uncaught SecurityError: Failed to read the 'cookie' property from 'Document': Cookies are disabled inside 'data:' URLs."

Despite ensuring the correctness of the session ID, the console errors persist. I've attempted to address the problem by setting appropriate headers in the loadRequest method, specifically including 'Content-Security-Policy' with 'sandbox allow-scripts allow-same-origin'. Unfortunately, this hasn't resolved the issue.

I've conducted searches for potential solutions or alternative methods, but no definitive solutions have surfaced.

If anyone has insights into what might be causing these issues or suggestions for resolving them, your assistance would be highly appreciated.

This is the whole code:

  <!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>
''';

class CheckoutPage extends StatefulWidget {
  final String sessionId;

  const CheckoutPage({Key? key, required this.sessionId}) : super(key: key);

  @override
  _CheckoutPageState createState() => _CheckoutPageState();
}

class _CheckoutPageState extends State<CheckoutPage> {
  late WebViewController _controller;

  @override
  void initState() {
    super.initState();
    _controller = WebViewController()
      ..clearCache()
      ..setJavaScriptMode(JavaScriptMode.unrestricted)
      ..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 == initialUrl) {
              _redirectToStripe();
            }
          }, onWebResourceError: ( error) {
            print(error);
          },
          ))

      ..loadRequest(
        Uri.parse(initialUrl), headers: {'Content-Security-Policy': 'sandbox allow-scripts allow-same-origin',},
      );
  }
  


  @override
  Widget build(BuildContext context) {
    return Scaffold(
      resizeToAvoidBottomInset: false,
      body: Container(
        padding: EdgeInsets.only(top: 30),
        child: WebViewWidget(
        controller: _controller,
      ),
      ),
    );
  }

  String get initialUrl =>
      'data:text/html;base64,${base64Encode(Utf8Encoder().convert(stripeHtmlPageScaffold))}';

  void _redirectToStripe() {
    final redirectToCheckoutJs = '''
      var stripe = Stripe(\'$stripePublicKey\');
      var sandbox="allow-same-origin allow-scripts";
      stripe.redirectToCheckout({
        sessionId: '${widget.sessionId}'
      }).then(function (result) {
        result.error.message = 'Error'
      });
    ''';
    _controller.runJavaScript(redirectToCheckoutJs);

  }
}
0

There are 0 answers