Search code examples
flutter-webflutterwebviewplugin

Loading url in web view doesn't work on web Flutter


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!

Solution

  • 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..