0

I'm using flutter_inappwebview: 6.0.0-beta.22 package and I'm opening the Stripe onboarding process in an in-app web view. While on Android emulator works as expected and the page is loaded, when I launch the web view on the web app(launched in release mode run -d chrome --release --web-hostname localhost --web-port 5000 ) the page doesn't load and on console I get the message

url is: https://connect.stripe.com/setup/c/acct_1MFXNcFwHPwkSrfO/jug2SEGbwzAq
NoSuchMethodError: method not found: 'toString' on null
js_primitives.dart:47     at a6J.aA (http://localhost:5000/main.dart.js?version=9:56217:6)
js_primitives.dart:47     at fY.Gq (http://localhost:5000/main.dart.js?version=9:82446:12)
js_primitives.dart:47     at fY.e0 (http://localhost:5000/main.dart.js?version=9:82409:6)
js_primitives.dart:47     at IQ.Cc (http://localhost:5000/main.dart.js?version=9:82306:3)
js_primitives.dart:47     at IQ.eK (http://localhost:5000/main.dart.js?version=9:82255:16)
js_primitives.dart:47     at IQ.e0 (http://localhost:5000/main.dart.js?version=9:82634:8)
js_primitives.dart:47     at Ai.Cc (http://localhost:5000/main.dart.js?version=9:82306:3)
js_primitives.dart:47     at Ai.eK (http://localhost:5000/main.dart.js?version=9:82255:16)
js_primitives.dart:47     at Ai.kE (http://localhost:5000/main.dart.js?version=9:82417:32)
js_primitives.dart:47     at Ai.wy (http://localhost:5000/main.dart.js?version=9:82382:6)

when clicking on any of the js_primitives.dart:47links on the right it shows this error

Could not load content for org-dartlang-sdk:///lib/_internal/js_runtime/lib/js_primitives.dart (Fetch through target failed: Unsupported URL scheme; Fallback: HTTP error: status code 404, net::ERR_UNKNOWN_URL_SCHEME)

Now, the url print is from the screen initState and is correct. This is the Screen:

import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
import 'package:universal_platform/universal_platform.dart';
import 'package:url_launcher/url_launcher_string.dart';
import '../utilities.dart';

class StripeOnboardScreen extends StatefulWidget {
  final String onboardUrl;
  const StripeOnboardScreen({Key? key, required this.onboardUrl})
      : super(key: key);

  @override
  State<StripeOnboardScreen> createState() => _StripeOnboardScreenState();
}

class _StripeOnboardScreenState extends State<StripeOnboardScreen> {
  dynamic backButton = UniversalPlatform.isWeb
      ? UniversalPlatform.isIOS
          ? CupertinoIcons.back
          : Icons.arrow_back
      : Icons.arrow_back;
  double fontSize = Utilities.fontSize;

  final GlobalKey webViewKey = GlobalKey();

  InAppWebViewController? webViewController;
InAppWebViewSettings settings = InAppWebViewSettings(
      javaScriptEnabled: true,
      javaScriptCanOpenWindowsAutomatically: true,
      useShouldOverrideUrlLoading: true,
      mediaPlaybackRequiresUserGesture: false,
      allowsInlineMediaPlayback: true,
      iframeAllow: "camera; microphone",
      iframeAllowFullscreen: true);
late PullToRefreshController pullToRefreshController;
  double progress = 0;
  // Create a webview controller to control the webview and get information
  // about its current state
  final urlController = TextEditingController();
  @override
  void initState() {
    super.initState();
    print('url is: ${widget.onboardUrl}');
    pullToRefreshController = (kIsWeb
        ? null
        : PullToRefreshController(
            settings: PullToRefreshSettings(
              color: Colors.blue,
            ),
          ))!;
  }

  @override
  void dispose() {
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Colors.transparent,
        elevation: 0,
        // Show a "Back" button in the app bar if the webview is displaying
        // a page other than the initial page
        leading: IconButton(
            icon: Icon(backButton),
            color: Colors.redAccent,
            onPressed: () {
              Navigator.pop(context);
            }),
      ),
      body: Container(
        height: MediaQuery.of(context).size.height,
        width: MediaQuery.of(context).size.width,
        child: InAppWebView(
          key: webViewKey,
          initialUrlRequest: URLRequest(
              url: WebUri(widget.onboardUrl, forceToStringRawValue: true)),
          initialSettings: settings,
          pullToRefreshController: pullToRefreshController,
          onWebViewCreated: (controller) {
            webViewController = controller;
          },
          onLoadStart: (controller, url) {
            setState(() {
              urlController.text = widget.onboardUrl;
            });
          },
          onPermissionRequest: (controller, request) async {
            return PermissionResponse(
                resources: request.resources,
                action: PermissionResponseAction.GRANT);
          },
          shouldOverrideUrlLoading: (controller, navigationAction) async {
            var uri = navigationAction.request.url!;

            if (![
              "http",
              "https",
              "file",
              "chrome",
              "data",
              "javascript",
              "about"
            ].contains(uri.scheme)) {
              await canLaunchUrlString(widget.onboardUrl)
                  ? await launchUrlString(widget.onboardUrl)
                  : throw 'Could not launch ${widget.onboardUrl}';
              // and cancel the request
              return NavigationActionPolicy.CANCEL;
            }
            return NavigationActionPolicy.ALLOW;
          },
          onConsoleMessage: (controller, consoleMessage) {
            print('consoleMessage is : $consoleMessage');
          },
        ),
      ),
    );
  }
}

I added the script in the head as per docs but here is the index.html so you can have look at it

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>fixit</title>

    <!--  <meta name="google-signin-client_id" content="YOUR_GOOGLE_SIGN_IN_OAUTH_CLIENT_ID.apps.googleusercontent.com">-->
    <meta name="google-signin-client_id"
          content="147151203258-clupo1g18oueig38uq8nts5mnkgug13e.apps.googleusercontent.com">
    <!--  <meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">-->
    <script type="application/javascript" src="/assets/packages/flutter_inappwebview/assets/web/web_support.js" defer></script>
</head>
<!--<body>-->
<body id="app-container">
<!-- The core Firebase JS SDK is always required and must be listed first -->
<script src="https://www.gstatic.com/firebasejs/8.10.1/firebase-app.js"></script>

<!-- TODO: Add SDKs for Firebase products that you want to use
     https://firebase.google.com/docs/web/setup#available-libraries -->
<script src="https://www.gstatic.com/firebasejs/8.10.1/firebase-auth.js"></script>
<script src="https://www.gstatic.com/firebasejs/8.10.1/firebase-analytics.js"></script>
<script src="https://www.gstatic.com/firebasejs/8.10.1/firebase-messaging.js"></script>
<script src="https://www.gstatic.com/firebasejs/8.10.1/firebase-storage.js"></script>
<script src="https://www.gstatic.com/firebasejs/8.10.1/firebase-database.js"></script>
<script src="https://www.gstatic.com/firebasejs/8.10.1/firebase-firestore.js"></script>
<script src="https://www.gstatic.com/firebasejs/8.10.1/firebase-remote-config.js"></script>
<script>
    // Your web app's Firebase configuration
    var firebaseConfig = {
      apiKey: "xx",
          authDomain: "xx",
          databaseURL: "xx",
          projectId: "xx",
          storageBucket: "xx",
          messagingSenderId: "xx",
          appId: "xx",
          measurementId: "xx"
    };
    // Initialize Firebase
    firebase.initializeApp(firebaseConfig);
<!--    firebase.analytics();-->

</script>
<script>
if ("serviceWorker" in navigator) {
  window.addEventListener("load", function () {
     //navigator.serviceWorker.register("/flutter_service_worker.js");
    navigator.serviceWorker.register("/firebase-messaging-sw.js");
  });
}

</script>
<script src="main.dart.js?version=9" type="application/javascript"></script>
</body>
</html>

Can you spot what I'm doing wrong?

this is my flutter doctor

[✓] Flutter (Channel stable, 3.3.9, on macOS 12.5.1 21G83 darwin-arm, locale en-IT)
    • Flutter version 3.3.9 on channel stable at /Users/vincenzocalia/development/flutter
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision b8f7f1f986 (3 weeks ago), 2022-11-23 06:43:51 +0900
    • Engine revision 8f2221fbef
    • Dart version 2.18.5
    • DevTools version 2.15.0

[✓] Android toolchain - develop for Android devices (Android SDK version 32.1.0-rc1)
    • Android SDK at /Users/vincenzocalia/Library/Android/sdk
    • Platform android-33, build-tools 32.1.0-rc1
    • Java binary at: /Applications/Android Studio.app/Contents/jre/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build 11.0.12+0-b1504.28-7817840)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 13.4.1)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Build 13F100
    • CocoaPods version 1.11.3

[✓] Chrome - develop for the web
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Android Studio (version 2021.2)
    • Android Studio at /Applications/Android Studio.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 11.0.12+0-b1504.28-7817840)

[✓] VS Code (version 1.73.1)
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension can be installed from:
      🔨 https://marketplace.visualstudio.com/items?itemName=Dart-Code.flutter

[✓] Connected device (3 available)
    • sdk gphone64 arm64 (mobile) • emulator-5554 • android-arm64  • Android 12 (API 31) (emulator)
    • macOS (desktop)             • macos         • darwin-arm64   • macOS 12.5.1 21G83 darwin-arm
    • Chrome (web)                • chrome        • web-javascript • Google Chrome 108.0.5359.124
                                                                                                                                                                                                                                              HTTP Host availability check is taking a long time...[✓] HTTP Host Availability
    • All required HTTP hosts are available

• No issues found!

1 Answer 1

1

Afters stripping down the Screen to the bare minimum (So no InAppWebViewController, PullToRefreshController, no callbacks) it finally displays the link. Unfortunately Stripe doesn't allow it to be in a iFrame so I get the web an ancestor violates the following Content Security Policy directive: "frame-ancestors 'self'.

So unless there is some settings to put in place for the plugin, I have to open it a new window for the app running on the web..

Sign up to request clarification or add additional context in comments.

9 Comments

I am in the process of attempting to do the exact same thing. Thank you for following up on this. You saved me a lot of time trying to get iframe to work for this. I'd like to pick your brain on how you finally solved connect onboarding.
No problem, just ask what you need to know. I know that Stripe APIs are quite deep and difficult. You have many choices about how to accept payments for example..SetupIntent/PaymentMethod(on device)+PaymentIntent(back end) vs. Checkout(this is only for front end security and ease) .. Let me know what you need to know. For onboarding use AccountLinks, generated on new Account creation and sent back with the response, that will need 2 urls a refresh and a return one, the return can be a deep link to your app ( I just build a web page to tell the the User that the onboarding was successful)
and as I didn't implement deep linking in my mobile app yet, the user just closes the new browser window on web or tab the back button and goes back to the previous app screen and he's back in the app on device. Actually it's the same behaviour of using await launchUrl( Uri.parse( 'https://onboarding-url'),mode: LaunchMode .externalApplication) so I might just get rid of StripeOnboardScreen and flutter_inappwebview altogether and just use launchUrl. 1 less screen + 1 less dependency = easier dev life. lol
I have the onboarding process working with my mobile app. I actually use launchUrl to do it. Now I'm trying to get my flutter web version to work. Right now it opens a new tab/window for onboarding. The problem I am having is how to communicate back to the web application. I've seen a few things about listening to background events, but I haven't dug into it yet. Have you built a Flutter web app with onboarding?
Hi, you have to launch the onboarding links from outside an app, Stipe doesn't allow iFrames, see my problem above. Also as I said I just don't link back to my apps using deep linking, I just display a page from my website telling the user that the onboarding was successful and he can close the browser and start using the app. This works exactly the same whether the user is on a tablet or on the browser, just launch the urls like await launchUrl( Uri.parse( 'https://onboarding-url'),mode: LaunchMode .externalApplication)
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.