Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

loadUrl didn't trigger again shouldOverrideUrlLoading on Android #2443

Open
1 of 2 tasks
EArminjon opened this issue Dec 3, 2024 · 1 comment
Open
1 of 2 tasks

loadUrl didn't trigger again shouldOverrideUrlLoading on Android #2443

EArminjon opened this issue Dec 3, 2024 · 1 comment
Labels
bug Something isn't working

Comments

@EArminjon
Copy link
Contributor

EArminjon commented Dec 3, 2024

Is there an existing issue for this?

  • I have searched the existing issues

Current Behavior

On iOS :

Redirecting using loadUrl:
Url is intercepted and the snackbar is well displayed

Redirecting using JS:
Url is intercepted and the snackbar is well displayed

On Android :

Redirecting using loadUrl:
Url is not intercepted and the snackbar not displayed

Redirecting using JS:
Url is intercepted and the snackbar is well displayed

Expected Behavior

On iOS :

Redirecting using loadUrl:
Url should be intercepted and the snackbar should well displayed

Redirecting using JS:
Url should be intercepted and the snackbar should well displayed

On Android :

Redirecting using loadUrl:
Url should be intercepted and the snackbar should well displayed

Redirecting using JS:
Url should be intercepted and the snackbar should well displayed

Steps with code example to reproduce

Steps with code example to reproduce
  1. Run the code bellow
  2. Ensure that floating action button is red
  3. Click on "Open our social network"
import 'dart:async';

import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';

void main() {
  runApp(const App());
}

class App extends StatelessWidget {
  const App({super.key});

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: Home(),
    );
  }
}

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

  @override
  State<Home> createState() => _HomeState();
}

class _HomeState extends State<Home> {
  final ValueNotifier<InAppWebViewController?> _controller =
      ValueNotifier<InAppWebViewController?>(null);
  final ValueNotifier<bool> _usingJS = ValueNotifier<bool>(false);
  final ValueNotifier<bool> _canGoBack = ValueNotifier<bool>(false);

  @override
  void dispose() {
    _controller.dispose();
    _usingJS.dispose();
    _canGoBack.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        leading: ValueListenableBuilder<bool>(
          valueListenable: _canGoBack,
          builder: (BuildContext context, bool canGoBack, _) {
            if (!canGoBack) return const SizedBox();

            return IconButton(
              icon: const Icon(Icons.arrow_back),
              onPressed: () => _controller.value?.goBack(),
            );
          },
        ),
        title: const Text('InAppWebview issue'),
      ),
      floatingActionButton: ValueListenableBuilder<bool>(
        valueListenable: _usingJS,
        builder: (BuildContext context, bool usingJS, _) =>
            FloatingActionButton.extended(
          onPressed: () => _usingJS.value = !_usingJS.value,
          backgroundColor: usingJS ? Colors.green : Colors.red,
          label: const Text('LoadUrl using JS'),
        ),
      ),
      body: SafeArea(
        child: Builder(
          builder: (BuildContext context) => InAppWebView(
            initialSettings: InAppWebViewSettings(
              javaScriptEnabled: true,
              useShouldOverrideUrlLoading: true,
              allowsBackForwardNavigationGestures: true,
            ),
            initialData: InAppWebViewInitialData(
              data: fakePage,
            ),
            onWebViewCreated: (_) => _onWebViewCreated(context, _),
            onLoadStop: (_, __) => _onLoadStop(context, _, __),
            shouldOverrideUrlLoading: (_, __) =>
                _shouldOverrideUrlLoading(context, _, __),
          ),
        ),
      ),
    );
  }

  void _onWebViewCreated(
    BuildContext context,
    InAppWebViewController controller,
  ) =>
      _controller.value = controller;

  Future<void> _onLoadStop(
    BuildContext context,
    InAppWebViewController controller,
    Uri? url,
  ) async =>
      _canGoBack.value = await controller.canGoBack();

  Future<NavigationActionPolicy> _shouldOverrideUrlLoading(
    BuildContext context,
    InAppWebViewController controller,
    NavigationAction navigationAction,
  ) async {
    final String url = navigationAction.request.url.toString();

    if (url.contains('https://random-url.com')) {
      if (_usingJS.value) {
        unawaited(
          controller.evaluateJavascript(
            source: 'window.location.href = "https://www.instagram.com";',
          ),
        );
      } else {
        unawaited(
          controller.loadUrl(
            urlRequest: URLRequest(
              url: WebUri('https://www.instagram.com'),
            ),
          ),
        );
      }

      return NavigationActionPolicy.CANCEL;
    } else if (url.contains('https://www.instagram.com')) {
      _openInstagramApp(context);
      return NavigationActionPolicy.CANCEL;
    }
    return NavigationActionPolicy.ALLOW;
  }

  void _openInstagramApp(BuildContext context) => ScaffoldMessenger.of(context)
    ..hideCurrentSnackBar()
    ..showSnackBar(const SnackBar(content: Text('Opening Instagram app')));
}

const String fakePage = '''
<!DOCTYPE html>
    <html lang="fr">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Page Simple</title>
        <style>
            body {
                display: flex;
                justify-content: center;
                align-items: center;
                height: 100vh;
                margin: 0;
                background-color: #f0f0f0;
            }
            button {
                padding: 15px 30px;
                font-size: 16px;
                color: white;
                background-color: #C13584; /* Couleur Instagram */
                border: none;
                border-radius: 5px;
                cursor: pointer;
            }
            button:hover {
                background-color: #E1306C; /* Couleur Instagram au survol */
            }
        </style>
    </head>
    <body>
        <button onclick="window.open('https://random-url.com', '_blank')">Open our social network</button>
    </body>
    </html>
''';

Stacktrace/Logs

Stacktrace/Logs for Android DEMO
D/EGL_emulation(17683): app_time_stats: avg=296.58ms min=35.08ms max=1010.04ms count=4
D/EGL_emulation(17683): app_time_stats: avg=64.05ms min=12.29ms max=829.02ms count=17
[AndroidInAppWebViewController] (android) WebView ID 0 calling "shouldOverrideUrlLoading" using {request: {headers: null, method: GET, networkServiceType: null, allowsConstrainedNetworkAccess: null, cachePolicy: null, body: null, url: https://random-url.com/, allowsExpensiveNetworkAccess: null, attribution: null, assumesHTTP3Capable: null, httpShouldUsePipelining: null, allowsCellularAccess: null, httpShouldHandleCookies: null, timeoutInterval: null, mainDocumentURL: null}, sourceFrame: null, isRedirect: false, targetFrame: null, hasGesture: true, shouldPerformDownload: null, isForMainFrame: true, navigationType: null}
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onWindowFocus" using []
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onWindowFocus" using []
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onProgressChanged" using {progress: 10}
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onProgressChanged" using {progress: 100}
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onProgressChanged" using {progress: 100}
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onProgressChanged" using {progress: 10}
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onConsoleMessage" using {messageLevel: 2, message: Error with Permissions-Policy header: Origin trial controlled feature not enabled: 'attribution-reporting'.}
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onConsoleMessage" using {messageLevel: 2, message: Error with Permissions-Policy header: Unrecognized feature: 'bluetooth'.}
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onConsoleMessage" using {messageLevel: 2, message: Error with Permissions-Policy header: Origin trial controlled feature not enabled: 'compute-pressure'.}
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onConsoleMessage" using {messageLevel: 2, message: Error with Permissions-Policy header: Unrecognized feature: 'hid'.}
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onConsoleMessage" using {messageLevel: 2, message: Error with Permissions-Policy header: Origin trial controlled feature not enabled: 'interest-cohort'.}
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onConsoleMessage" using {messageLevel: 2, message: Error with Permissions-Policy header: Unrecognized feature: 'local-fonts'.}
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onConsoleMessage" using {messageLevel: 2, message: Error with Permissions-Policy header: Unrecognized feature: 'otp-credentials'.}
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onConsoleMessage" using {messageLevel: 2, message: Error with Permissions-Policy header: Unrecognized feature: 'payment'.}
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onConsoleMessage" using {messageLevel: 2, message: Error with Permissions-Policy header: Unrecognized feature: 'serial'.}
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onConsoleMessage" using {messageLevel: 2, message: Error with Permissions-Policy header: Origin trial controlled feature not enabled: 'shared-storage'.}
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onConsoleMessage" using {messageLevel: 2, message: Error with Permissions-Policy header: Origin trial controlled feature not enabled: 'shared-storage-select-url'.}
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onConsoleMessage" using {messageLevel: 2, message: Error with Permissions-Policy header: Unrecognized feature: 'usb'.}
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onConsoleMessage" using {messageLevel: 2, message: Error with Permissions-Policy header: Unrecognized feature: 'xr-spatial-tracking'.}
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onConsoleMessage" using {messageLevel: 3, message: The Content Security Policy directive 'upgrade-insecure-requests' is ignored when delivered in a report-only policy.}
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onLoadStart" using {url: https://www.instagram.com/}
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onUpdateVisitedHistory" using {isReload: false, url: https://www.instagram.com/}
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onProgressChanged" using {progress: 25}
I/TRuntime.CctTransportBackend(17683): Making request to: https://firebaselogging-pa.googleapis.com/v1/firelog/legacy/batchlog
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onProgressChanged" using {progress: 65}
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onTitleChanged" using {title: Instagram}
I/TRuntime.CctTransportBackend(17683): Status Code: 200
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onPageCommitVisible" using {url: https://www.instagram.com/}
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onUpdateVisitedHistory" using {isReload: false, url: https://www.instagram.com/}
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onLoadStop" using {url: https://www.instagram.com/}
D/EGL_emulation(17683): app_time_stats: avg=739.24ms min=46.94ms max=2757.25ms count=4
D/EGL_emulation(17683): app_time_stats: avg=738.69ms min=29.32ms max=2760.17ms count=4
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onProgressChanged" using {progress: 80}
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onReceivedTouchIconUrl" using {precomposed: false, url: https://static.cdninstagram.com/rsrc.php/v3/yG/r/De-Dwpd5CHc.png}
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onReceivedTouchIconUrl" using {precomposed: false, url: https://static.cdninstagram.com/rsrc.php/v3/yB/r/-7Z_RkdLJUX.png}
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onReceivedTouchIconUrl" using {precomposed: false, url: https://static.cdninstagram.com/rsrc.php/v3/yx/r/H1l_HHqi4p6.png}
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onReceivedTouchIconUrl" using {precomposed: false, url: https://static.cdninstagram.com/rsrc.php/v3/ys/r/aM-g435MtEX.png}
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onReceivedTouchIconUrl" using {precomposed: false, url: https://static.cdninstagram.com/rsrc.php/v3/yR/r/lam-fZmwmvn.png}
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onProgressChanged" using {progress: 100}
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onProgressChanged" using {progress: 100}
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onLoadStop" using {url: https://www.instagram.com/}
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onConsoleMessage" using {messageLevel: 1, message: 
%cStop! font-family:helvetica; font-size:20px; font-size:50px; font-weight:bold; color:red; -webkit-text-stroke:1px black;}
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onConsoleMessage" using {messageLevel: 1, message: 
%cThis is a browser feature intended for developers. If someone told you to copy-paste something here to enable an Instagram feature or "hack" someone's account, it is a scam and will give them access to your Instagram account. font-family:helvetica; font-size:20px; }
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onConsoleMessage" using {messageLevel: 1, message: 
%cSee https://www.facebook.com/selfxss for more information. font-family:helvetica; font-size:20px; }
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onConsoleMessage" using {messageLevel: 1, message: 
%c }
D/EGL_emulation(17683): app_time_stats: avg=89.84ms min=10.34ms max=906.17ms count=18
D/EGL_emulation(17683): app_time_stats: avg=342.54ms min=16.42ms max=963.61ms count=3
D/EGL_emulation(17683): app_time_stats: avg=342.57ms min=16.81ms max=960.81ms count=3
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onProgressChanged" using {progress: 10}
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onLoadStart" using {url: about:blank}
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onUpdateVisitedHistory" using {isReload: false, url: about:blank}
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onProgressChanged" using {progress: 80}
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onProgressChanged" using {progress: 100}
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onProgressChanged" using {progress: 100}
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onTitleChanged" using {title: Page Simple}
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onLoadStop" using {url: about:blank}
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onPageCommitVisible" using {url: about:blank}
D/EGL_emulation(17683): app_time_stats: avg=83.68ms min=7.26ms max=765.85ms count=12
D/EGL_emulation(17683): app_time_stats: avg=66.91ms min=13.39ms max=767.00ms count=15
D/EGL_emulation(17683): app_time_stats: avg=66.74ms min=11.56ms max=769.76ms count=15
[AndroidInAppWebViewController] (android) WebView ID 0 calling "shouldOverrideUrlLoading" using {request: {headers: null, method: GET, networkServiceType: null, allowsConstrainedNetworkAccess: null, cachePolicy: null, body: null, url: https://random-url.com/, allowsExpensiveNetworkAccess: null, attribution: null, assumesHTTP3Capable: null, httpShouldUsePipelining: null, allowsCellularAccess: null, httpShouldHandleCookies: null, timeoutInterval: null, mainDocumentURL: null}, sourceFrame: null, isRedirect: false, targetFrame: null, hasGesture: true, shouldPerformDownload: null, isForMainFrame: true, navigationType: null}
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onProgressChanged" using {progress: 10}
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onProgressChanged" using {progress: 100}
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onProgressChanged" using {progress: 100}
[AndroidInAppWebViewController] (android) WebView ID 0 calling "shouldOverrideUrlLoading" using {request: {headers: null, method: GET, networkServiceType: null, allowsConstrainedNetworkAccess: null, cachePolicy: null, body: null, url: https://www.instagram.com/, allowsExpensiveNetworkAccess: null, attribution: null, assumesHTTP3Capable: null, httpShouldUsePipelining: null, allowsCellularAccess: null, httpShouldHandleCookies: null, timeoutInterval: null, mainDocumentURL: null}, sourceFrame: null, isRedirect: false, targetFrame: null, hasGesture: false, shouldPerformDownload: null, isForMainFrame: true, navigationType: null}
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onProgressChanged" using {progress: 10}
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onProgressChanged" using {progress: 100}
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onProgressChanged" using {progress: 100}
D/EGL_emulation(17683): app_time_stats: avg=21.30ms min=8.25ms max=128.84ms count=47
D/EGL_emulation(17683): app_time_stats: avg=22.10ms min=7.76ms max=273.39ms count=46
D/EGL_emulation(17683): app_time_stats: avg=22.10ms min=4.60ms max=272.68ms count=46

Flutter version

3.24.3

Operating System, Device-specific and/or Tool

Flutter doctor -v
[✓] Flutter (Channel stable, 3.24.3, on macOS 15.0.1 24A348 darwin-arm64, locale fr-FR)
    • Flutter version 3.24.3 on channel stable at /Users/earminjon/fvm/versions/3.24.3
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision 2663184aa7 (3 months ago), 2024-09-11 16:27:48 -0500
    • Engine revision 36335019a8
    • Dart version 3.5.3
    • DevTools version 2.37.3

[✓] Android toolchain - develop for Android devices (Android SDK version 35.0.0)
    • Android SDK at /Users/earminjon/Library/Android/Sdk
    • Platform android-35, build-tools 35.0.0
    • ANDROID_HOME = /Users/earminjon/Library/Android/Sdk
    • Java binary at: /Users/earminjon/Applications/Android Studio.app/Contents/jbr/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build 17.0.11+0-17.0.11b1207.24-11852314)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 16.0)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Build 16A242d
    • CocoaPods version 1.14.3

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

[✓] Android Studio (version 2024.1)
    • Android Studio at /Users/earminjon/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.11+0-17.0.11b1207.24-11852314)

[✓] Android Studio (version 2023.2)
    • Android Studio at /Users/perso/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)

[✓] IntelliJ IDEA Ultimate Edition (version 2024.2.3)
    • IntelliJ at /Users/earminjon/Applications/IntelliJ IDEA Ultimate.app
    • Flutter plugin version 82.1.3
    • Dart plugin version 242.22855.32

[✓] Connected device (5 available)
    • sdk gphone64 arm64 (mobile)     • emulator-5554                        • android-arm64  • Android 15 (API 35) (emulator)
    • iPhone 16 Plus (mobile)         • A99393A6-DE51-45D5-8E1E-B077F59C1E57 • ios            •
      com.apple.CoreSimulator.SimRuntime.iOS-18-0 (simulator)
    • macOS (desktop)                 • macos                                • darwin-arm64   • macOS 15.0.1 24A348 darwin-arm64
    • Mac Designed for iPad (desktop) • mac-designed-for-ipad                • darwin         • macOS 15.0.1 24A348 darwin-arm64

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

Plugin version

6.1.1

Additional information

iOS DEMO :

ios_demo.mp4

Android DEMO :

android_demo.mp4

Self grab

  • I'm ready to work on this issue!
@EArminjon EArminjon added the bug Something isn't working label Dec 3, 2024
@EArminjon EArminjon changed the title loadUrl didn't trigger loadUrl didn't trigger again shouldOverrideUrlLoading Dec 3, 2024
@EArminjon EArminjon changed the title loadUrl didn't trigger again shouldOverrideUrlLoading loadUrl didn't trigger again shouldOverrideUrlLoading on Android Dec 3, 2024
@laishere
Copy link

I think it's the expected behavior of both Android and iOS. Android won't call shouldOverrideUrlLoading for the request open with loadUrl, but iOS will call webView(_:decidePolicyFor:decisionHandler:). The official flutter webview does the same too.
flutter/flutter#39441 (comment)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants