Birto
Birto

Reputation: 91

Flutter InAppWebView: Google Sign-In Redirects to Blank Page

Problem Description

I'm trying to reuse the login stack of my website (lirmusic.com, which uses ThirdWeb) in my Flutter app using the inappwebview package. The flow should work as follows:

  1. User wants to log in, an InAppWebView opens to lirmusic.com/mobileLogin
  2. User logs in as if they were on the website
  3. Upon successful login, the website launches a URL call to lirmusic.com/firebaseToken=xxxxxx
  4. I capture this Firebase token and use it to log in to my app with the firebase_auth package

Current Status:

Issue: When choosing Google login, it opens the account selection page, but after selecting an account, it remains stuck on a white page instead of redirecting back to lirmusic.com/firebaseToken.

Code

class TestNewWeb extends StatefulWidget {
  const TestNewWeb({super.key});

  @override
  State<TestNewWeb> createState() => _TestNewWebState();
}

class _TestNewWebState extends State<TestNewWeb> {
  final GlobalKey webViewKey = GlobalKey();

  InAppWebViewController? webViewController;
  InAppWebViewSettings settings = InAppWebViewSettings(
    cacheEnabled: true,
    isInspectable: kDebugMode,
    mediaPlaybackRequiresUserGesture: false,
    //supportMultipleWindows: true,
    //javaScriptCanOpenWindowsAutomatically: true,
    allowsInlineMediaPlayback: true,
    javaScriptEnabled: true,
    iframeAllow: "camera; microphone",
    iframeAllowFullscreen: true,
    userAgent: 'random',
  );

  PullToRefreshController? pullToRefreshController;
  String url = "";
  double progress = 0;
  final urlController = TextEditingController();

  @override
  void initState() {
    super.initState();

    pullToRefreshController = kIsWeb
        ? null
        : PullToRefreshController(
            settings: PullToRefreshSettings(
              color: Colors.blue,
            ),
            onRefresh: () async {
              if (defaultTargetPlatform == TargetPlatform.android) {
                webViewController?.reload();
              } else if (defaultTargetPlatform == TargetPlatform.iOS) {
                webViewController?.loadUrl(
                    urlRequest:
                        URLRequest(url: await webViewController?.getUrl()));
              }
            },
          );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(title: const Text("InAppWebView")),
        body: SafeArea(
            child: Column(children: <Widget>[
          TextField(
            decoration: const InputDecoration(prefixIcon: Icon(Icons.search)),
            controller: urlController,
            keyboardType: TextInputType.url,
            onSubmitted: (value) {
              var url = WebUri(value);
              if (url.scheme.isEmpty) {
                url = WebUri("https://lirmusic.com/mobileLogin");
              }
              webViewController?.loadUrl(urlRequest: URLRequest(url: url));
            },
          ),
          Expanded(
            child: Stack(
              children: [
                InAppWebView(
                    key: webViewKey,
                    initialUrlRequest: URLRequest(url: WebUri(lir)),
                    initialSettings: settings,
                    pullToRefreshController: pullToRefreshController,
                    onWebViewCreated: (controller) {
                      webViewController = controller;
                    },
                    onLoadStart: (controller, url) {
                      print("URL ----------" + url.toString());
                      setState(() {
                        this.url = url.toString();
                        urlController.text = this.url;
                      });
                    },
                    //onPermissionRequest: (controller, request) async {
                    //  return PermissionResponse(
                    //      resources: request.resources,
                    //      action: PermissionResponseAction.GRANT);
                    //},
                    onCreateWindow: (controller, createWindowAction) async {
                      if (createWindowAction.request.url
                          .toString()
                          .contains("login/google")) {
                        showDialog(
                          context: context,
                          builder: (context) {
                            return WindowPopup(
                                createWindowAction: createWindowAction);
                          },
                        );
                      }
                    },
                    shouldOverrideUrlLoading:
                        (controller, navigationAction) async {
                      // https://embedded-wallet.thirdweb.com/api/2024-05-05/login/google?clientId=f3b0d40edd0251e2ba4a9ef3a20fa268

                      return NavigationActionPolicy.ALLOW;
                    },
                    onLoadStop: (controller, url) async {
                      pullToRefreshController?.endRefreshing();
                      setState(() {
                        this.url = url.toString();
                        urlController.text = this.url;
                      });
                    },
                    onReceivedError: (controller, request, error) {
                      pullToRefreshController?.endRefreshing();
                    },
                    onProgressChanged: (controller, progress) {
                      if (progress == 100) {
                        pullToRefreshController?.endRefreshing();
                      }
                      setState(() {
                        this.progress = progress / 100;
                        urlController.text = url;
                      });
                    },
                    onUpdateVisitedHistory:
                        (controller, url, androidIsReload) async {
                      String? token = extractTokenFromUrl(url.toString());
                      if (token != null) {
                        final userCredential =
                            await loginWithFirebaseToken(token);
                        if (kDebugMode) {
                          print("debug: ${userCredential.user}");
                        }
                        // Clear cookies and cache. Important for forgetting the login.
                        await CookieManager.instance().deleteAllCookies();
                        await controller.clearCache();
                        Navigator.pop(context, token);
                      }
                      setState(() {
                        this.url = url.toString();
                        urlController.text = this.url;
                      });
                    },
                    onConsoleMessage: (controller, consoleMessage) {
                      if (kDebugMode) {
                        print(consoleMessage);
                      }
                    },
                    onReceivedHttpError: (controller, request, errorResponse) {
                      if (kDebugMode) {
                        print("albi $errorResponse");
                      }
                    },
                    onPageCommitVisible: (controller, url) async {
                      if (url != null &&
                          getCookieString(url.rawValue) != null) {
                        final cookieString = getCookieString(url.rawValue);
                        await loginWithFirebaseToken(cookieString!);
                        Navigator.pop(context);
                      }
                    }),
                progress < 1.0
                    ? LinearProgressIndicator(value: progress)
                    : Container(),
              ],
            ),
          ),
          ButtonBar(
            alignment: MainAxisAlignment.center,
            children: <Widget>[
              ElevatedButton(
                child: const Icon(Icons.arrow_back),
                onPressed: () {
                  webViewController?.goBack();
                },
              ),
              ElevatedButton(
                child: const Icon(Icons.arrow_forward),
                onPressed: () {
                  webViewController?.goForward();
                },
              ),
              ElevatedButton(
                child: const Icon(Icons.refresh),
                onPressed: () {
                  webViewController?.reload();
                },
              ),
            ],
          ),
        ])));
  }
}

What I've Tried

  1. Implemented onCreateWindow to handle the Google login popup
  2. Enabled supportMultipleWindows and javaScriptCanOpenWindowsAutomatically in InAppWebViewSettings
  3. Checked console messages and HTTP errors, but found no relevant information

Environment

[✓] Flutter (Channel stable, 3.22.1, on macOS 14.5 23F79 darwin-arm64, locale
    it-IT)
    • Flutter version 3.22.1 on channel stable at /Users/albertonoris/flutter
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision a14f74ff3a (4 months ago), 2024-05-22 11:08:21 -0500
    • Engine revision 55eae6864b
    • Dart version 3.4.1
    • DevTools version 2.34.3

[✓] Android toolchain - develop for Android devices (Android SDK version
    34.0.0)
    • Android SDK at /Users/albertonoris/Library/Android/sdk
    • Platform android-34, build-tools 34.0.0
    • Java binary at: /Applications/Android
      Studio.app/Contents/jbr/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build
      17.0.9+0-17.0.9b1087.7-11185874)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 15.4)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Build 15F31d
    • CocoaPods version 1.15.2

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

[✓] Android Studio (version 2023.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
      17.0.9+0-17.0.9b1087.7-11185874)

[✓] VS Code (version 1.84.2)
    • VS Code at /Users/albertonoris/Downloads/Visual Studio
      Code.app/Contents
    • Flutter extension version 3.96.0

[✓] Connected device (5 available)
    • sdk gphone64 arm64 (mobile)     • emulator-5554             •
      android-arm64  • Android 14 (API 34) (emulator)
    • Aifon di Albi (mobile)          • 00008120-00045CEE0240C01E • ios
      • iOS 17.6 21G80
    • macOS (desktop)                 • macos                     •
      darwin-arm64   • macOS 14.5 23F79 darwin-arm64
    • Mac Designed for iPad (desktop) • mac-designed-for-ipad     • darwin
      • macOS 14.5 23F79 darwin-arm64
    • Chrome (web)                    • chrome                    •
      web-javascript • Google Chrome 128.0.6613.120
    ! Error: Browsing on the local area network for iPad di Alberto. Ensure
      the device is unlocked and attached with a cable or associated with the
      same local area network as this Mac.
      The device must be opted into Developer Mode to connect wirelessly.
      (code -27)

[✓] Network resources
    • All expected network resources are available.

• No issues found!

Any insights or solutions would be greatly appreciated!

Upvotes: 2

Views: 125

Answers (0)

Related Questions