WebView v4 loadFile not working on iOS

This issue has been tracked since 2023-03-19.

When loading an HTML file from Application Documents into WebViewWidget, the file seems to load fine on Android, however, it does not load at all on iOS. Upon removing the setNavigationDelegate, it loads fine on both platforms.
I have not found any indication or official documentation anywhere to this behavior - including the new usage tutorial for WebView v4.
Note: tests for both platforms were ran on physical devices.

Steps to Reproduce

  1. Execute flutter run on the code sample

Expected results:
One of two possibilities:
Ideally, the HTML content to display on both Android and iOS.
Otherwise, an indication of the iOS limitation in the provided code example "Instantiating a WebViewController." or somewhere in the README.

Actual results:
Android WebView:
Screenshot_20230319_112353

iOS WebView:
IMG_8548

Code sample
import 'dart:io';

import 'package:flutter/material.dart';
import 'package:path/path.dart';
import 'package:path_provider/path_provider.dart';
import 'package:url_launcher/url_launcher_string.dart';
import 'package:webview_flutter/webview_flutter.dart';

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

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});
  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  late WebViewController webViewController;
  bool _ready = false;

  @override
  void initState() {
    super.initState();
    webViewController = WebViewController()
      ..enableZoom(false)
      ..setJavaScriptMode(JavaScriptMode.unrestricted)
      ..setNavigationDelegate(
        NavigationDelegate(
          onNavigationRequest: (navigation) {
            if (navigation.url == 'about:blank') {
              return NavigationDecision.navigate;
            } else {
              debugPrint(navigation.url);
              launchUrlString(navigation.url, mode: LaunchMode.externalApplication);
              return NavigationDecision.prevent;
            }
          },
          onPageStarted: (value) {
            //
          },
          onPageFinished: (value) {
            //
          },
          onProgress: (value) {
            //
          },
          onWebResourceError: (err) {
            //
          },
        ),
      );
    setFile();
  }

  void setFile() async {
    Directory dir = await getApplicationDocumentsDirectory();
    String filepath = join(dir.path, 'index.html');
    File file = File(filepath);
    String fileHtml = '''
      <!DOCTYPE html>
      <html lang="en">
      <head>
        <meta charset="UTF-8">
        <title>Webview4 Test iOS Bug</title>
      </head>
      <body>
        <div style="font-size:45px;">
          <p>Lorem ipsum dolor....</p>
        </div>
      </body>
      </html>
    ''';
    await file.writeAsString(fileHtml);

    webViewController.loadFile(join(dir.path, 'index.html'));
    setState(() {
      _ready = true;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: _ready
          ? Center(
              child: WebViewWidget(
                controller: webViewController,
              ),
            )
          : const CircularProgressIndicator(),
    );
  }
}
Logs

ios:

[        ] Application launched on the device. Waiting for observatory url.
[+1061 ms] Observatory URL on device: http://127.0.0.1:56838/
[        ] Attempting to forward device port 56838 to host port 59770
[        ] executing: /Users/lielvdh/Developer/flutter/bin/cache/artifacts/usbmuxd/iproxy 59770:56838 --udid 00008030-001631D60CF2802E --debug
[ +941 ms] flutter: file:///var/mobile/Containers/Data/Application/CDAE00F4-184A-4383-BCB2-6E7E1DC3E2F0/Documents/index.html
[  +68 ms] Forwarded port ForwardedPort HOST:59770 to DEVICE:56838
[   +1 ms] Forwarded host port 59770 to device port 56838 for Observatory
[   +2 ms] Installing and launching... (completed in 22.9s)
[        ] Caching compiled dill
[  +48 ms] Connecting to service protocol: http://127.0.0.1:59770/
[  +80 ms] Launching a Dart Developer Service (DDS) instance at http://127.0.0.1:0, connecting to VM service at http://127.0.0.1:59770/.
[  +48 ms] DDS is listening at http://127.0.0.1:59773/JIwBjSBpWu4=/.
[  +11 ms] Successfully connected to service protocol: http://127.0.0.1:59770/
[  +18 ms] DevFS: Creating new filesystem on the device (null)
[  +17 ms] DevFS: Created new filesystem on the device (file:///private/var/mobile/Containers/Data/Application/CDAE00F4-184A-4383-BCB2-6E7E1DC3E2F0/tmp/webview4_ios_bugOUcdUp/webview4_ios_bug/)
[   +4 ms] Updating assets
[  +82 ms] Syncing files to device  Liel's iPhone..
[        ] Compiling dart to kernel with 0 updated files
[        ] Processing bundle.
[        ] <- recompile package:webview4_ios_bug/main.dart 49ec3ef1-438b-43cc-a63d-b8a2457e43af
[        ] <- 49ec3ef1-438b-43cc-a63d-b8a2457e43af
[        ] Bundle processing done.
[  +76 ms] Updating files.
[        ] DevFS: Sync finished
[        ] Syncing files to device Liel's iPhone... (completed in 78ms)
[        ] Synced 0.0MB.
[        ] <- accept
[   +4 ms] Connected to _flutterView/0x126836020.

android:

Observatory URL on device: http://127.0.0.1:40887/3vwnOx9e-ko=/
[        ] executing: /Users/lielvdh/Library/Android/sdk/platform-tools/adb -s RZCT310HAMK forward tcp:0 tcp:40887
[  +19 ms] 59834
[        ] Forwarded host port 59834 to device port 40887 for Observatory
[   +2 ms] Caching compiled dill
[  +17 ms] Connecting to service protocol: http://127.0.0.1:59834/3vwnOx9e-ko=/
[ +132 ms] Launching a Dart Developer Service (DDS) instance at http://127.0.0.1:0, connecting to VM service at http://127.0.0.1:59834/3vwnOx9e-ko=/.
[  +94 ms] DDS is listening at http://127.0.0.1:59839/4iHBnnkonN8=/.
[  +26 ms] Successfully connected to service protocol: http://127.0.0.1:59834/3vwnOx9e-ko=/
[  +40 ms] DevFS: Creating new filesystem on the device (null)
[  +16 ms] DevFS: Created new filesystem on the device (file:///data/user/0/com.example.webview4_ios_bug/code_cache/webview4_ios_bugFZWLUD/webview4_ios_bug/)
[        ] Updating assets
[  +47 ms] Syncing files to device SM G781B...
[        ] Compiling dart to kernel with 0 updated files
[        ] Processing bundle.
[        ] <- recompile package:webview4_ios_bug/main.dart a2615fa9-b71f-4b8d-95f6-d6b4c518eb7f
[        ] <- a2615fa9-b71f-4b8d-95f6-d6b4c518eb7f
[        ] Bundle processing done.
[  +68 ms] Updating files.
[        ] DevFS: Sync finished
[        ] Syncing files to device SM G781B... (completed in 70ms)
[        ] Synced 0.0MB.
[        ] <- accept
[   +3 ms] Connected to _flutterView/0xb400007ac2e31620.
[   +1 ms] Flutter run key commands.
[        ] r Hot reload. πŸ”₯πŸ”₯πŸ”₯
[        ] R Hot restart.
[        ] h List all available interactive commands.
[        ] d Detach (terminate "flutter run" but leave application running).
[        ] c Clear the screen
[        ] q Quit (terminate the application on the device).
[        ] πŸ’ͺ Running with sound null safety πŸ’ͺ
[        ] An Observatory debugger and profiler on SM G781B is available at: http://127.0.0.1:59839/4iHBnnkonN8=/
[  +15 ms] W/ziparchive(13557): Unable to open '/data/app/~~czt7Ncg6_99IbvQGBCqk6w==/com.google.android.trichromelibrary_548115434-U-tC4p3PGV-Pg_BroAcJ3Q==/base.dm': No such file or directory
[        ] W/ziparchive(13557): Unable to open '/data/app/~~czt7Ncg6_99IbvQGBCqk6w==/com.google.android.trichromelibrary_548115434-U-tC4p3PGV-Pg_BroAcJ3Q==/base.dm': No such file or directory
[   +6 ms] W/ebview4_ios_bug(13557): Entry not found
[        ] D/nativeloader(13557): Configuring classloader-namespace for other apk /data/app/~~czt7Ncg6_99IbvQGBCqk6w==/com.google.android.trichromelibrary_548115434-U-tC4p3PGV-Pg_BroAcJ3Q==/base.apk. target_sdk_version=33,
uses_libraries=ALL,
library_path=/data/app/~~moVPjD1eXN9Yiq5T8dD4FQ==/com.google.android.webview-dSjjqyT_dsMt35WtBxafaA==/lib/arm64:/data/app/~~moVPjD1eXN9Yiq5T8dD4FQ==/com.google.android.webview-dSjjqyT_dsMt35WtBxafaA==/base.apk!/lib/arm64-v8a:/data/a
pp/~~czt7Ncg6_99IbvQGBCqk6w==/com.google.android.trichromelibrary_548115434-U-tC4p3PGV-Pg_BroAcJ3Q==/base.apk!/lib/arm64-v8a, permitted_path=/data:/mnt/expand
[        ] D/nativeloader(13557): Extending system_exposed_libraries:
libhumantracking.arcsoft.so:libPortraitDistortionCorrection.arcsoft.so:libPortraitDistortionCorrectionCali.arcsoft.so:libface_landmark.arcsoft.so:libFacialStickerEngine.arcsoft.so:libveengine.arcsoft.so:lib_pet_detection.arcsoft.so:
libhigh_res.arcsoft.so:libimage_enhancement.arcsoft.so:liblow_light_hdr.arcsoft.so:libhigh_dynamic_range.arcsoft.so:libsuperresolution.arcsoft.so:libFacialAttributeDetection.arcsoft.so:libBeauty_v4.camera.samsung.so:libexifa.camera.
samsung.so:libjpega.camera.samsung.so:libOpenCv.camera.samsung.so:libVideoClassifier.camera.samsung.so:libtensorflowLite.dynamic_viewing.camera.samsung.so:libImageScreener.camera.samsung.so:libMyFilter.camera.samsung.so:libtflite2.m
yfilters.camera.samsung.so:libHIDTSnapJNI.camera.samsung.so:libSmartScan.camera.samsung.so:libRectify.camera.samsung.so:libDocRectifyWrapper.camera.samsung.so:libUltraWideDistortionCorrection.camera.samsung.so:libHpr_RecGAE_cvFeatur
e_v1.0.camera.samsung.so:libHprFace_GAE_api.camera.samsung.
[        ] D/nativeloader(13557): Configuring classloader-namespace for other apk /data/app/~~moVPjD1eXN9Yiq5T8dD4FQ==/com.google.android.webview-dSjjqyT_dsMt35WtBxafaA==/base.apk. target_sdk_version=33, uses_libraries=,
library_path=/data/app/~~moVPjD1eXN9Yiq5T8dD4FQ==/com.google.android.webview-dSjjqyT_dsMt35WtBxafaA==/lib/arm64:/data/app/~~moVPjD1eXN9Yiq5T8dD4FQ==/com.google.android.webview-dSjjqyT_dsMt35WtBxafaA==/base.apk!/lib/arm64-v8a:/data/a
pp/~~czt7Ncg6_99IbvQGBCqk6w==/com.google.android.trichromelibrary_548115434-U-tC4p3PGV-Pg_BroAcJ3Q==/base.apk!/lib/arm64-v8a, permitted_path=/data:/mnt/expand
[        ] I/WebViewFactory(13557): Loading com.google.android.webview version 110.0.5481.154 (code 548115434)
[   +5 ms] W/ebview4_ios_bug(13557): Accessing hidden method Landroid/os/Trace;->isTagEnabled(J)Z (unsupported, reflection, allowed)
[        ] W/ebview4_ios_bug(13557): Accessing hidden method Landroid/os/Trace;->traceBegin(JLjava/lang/String;)V (unsupported, reflection, allowed)
[        ] W/ebview4_ios_bug(13557): Accessing hidden method Landroid/os/Trace;->traceEnd(J)V (unsupported, reflection, allowed)
[        ] W/ebview4_ios_bug(13557): Accessing hidden method Landroid/os/Trace;->asyncTraceBegin(JLjava/lang/String;I)V (unsupported, reflection, allowed)
[        ] W/ebview4_ios_bug(13557): Accessing hidden method Landroid/os/Trace;->asyncTraceEnd(JLjava/lang/String;I)V (unsupported, reflection, allowed)
[        ] I/ebview4_ios_bug(13557): Compiler allocated 6133KB to compile void android.view.ViewRootImpl.performTraversals()
[   +1 ms] I/cr_WVCFactoryProvider(13557): Loaded version=110.0.5481.154 minSdkVersion=29 isBundle=true multiprocess=true packageId=2
[   +9 ms] I/cr_LibraryLoader(13557): Successfully loaded native library
[        ] I/cr_CachingUmaRecorder(13557): Flushed 9 samples from 9 histograms.
[  +12 ms] D/CompatibilityChangeReporter(13557): Compat change id reported: 183155436; UID 10726; state: DISABLED
[  +21 ms] W/chromium(13557): [WARNING:dns_config_service_android.cc(115)] Failed to read DnsConfig.
[  +21 ms] D/CompatibilityChangeReporter(13557): Compat change id reported: 214741472; UID 10726; state: DISABLED
[   +8 ms] D/CompatibilityChangeReporter(13557): Compat change id reported: 171228096; UID 10726; state: ENABLED
[ +213 ms] The Flutter DevTools debugger and profiler on SM G781B is available at: http://127.0.0.1:9101?uri=http://127.0.0.1:59839/4iHBnnkonN8=/
[   +6 ms] W/ebview4_ios_bug(13557): Accessing hidden method Landroid/media/AudioManager;->getOutputLatency(I)I (unsupported, reflection, allowed)
[   +2 ms] W/cr_media(13557): BLUETOOTH_CONNECT permission is missing.
[        ] W/cr_media(13557): registerBluetoothIntentsIfNeeded: Requires BLUETOOTH permission
[  +64 ms] I/PlatformViewsController(13557): Hosting view in view hierarchy for platform view: 0
[   +1 ms] D/NativeCustomFrequencyManager(13557): [NativeCFMS] BpCustomFrequencyManager::BpCustomFrequencyManager()
[        ] D/OpenGLRenderer(13557): eglCreateWindowSurface
[   +5 ms] E/FrameEvents(13557): updateAcquireFence: Did not find frame.
[   +2 ms] D/OpenGLRenderer(13557): CFMS:: SetUp Pid : 13557    Tid : 13582
[   +2 ms] W/Parcel  (13557): Expecting binder but got null!
[   +4 ms] I/BLASTBufferQueue(13557): [SurfaceView[com.example.webview4_ios_bug/com.example.webview4_ios_bug.MainActivity]@0#1](f:0,a:0) onFrameAvailable the first frame is available
[  +18 ms] D/CompatibilityChangeReporter(13557): Compat change id reported: 193247900; UID 10726; state: DISABLED
[        ] D/[email protected](13557):  setAlpha: mUseAlpha = false alpha=1.0
[        ] D/[email protected](13557):  updateSurfaceAlpha: setUseAlpha() is not called, ignored.
[   +1 ms] I/[email protected][MainActivity](13557): Setup new sync id=0
[        ] I/[email protected][MainActivity](13557): Setting syncFrameCallback
[        ] E/SurfaceSyncer(13557): Failed to find sync for id=0
[        ] I/[email protected][MainActivity](13557): registerCallbacksForSync syncBuffer=false
[  +19 ms] E/FrameEvents(13557): updateAcquireFence: Did not find frame.
[        ] D/[email protected](13557): updateSurfacePosition RenderWorker, frameNr = 1, position = [0, 0, 1080, 2256] surfaceSize = 1080x2256
[        ] I/[email protected](13557): uSP: rtp = Rect(0, 0 - 1080, 2256) rtsw = 1080 rtsh = 2256
[        ] I/[email protected](13557): onSSPAndSRT: pl = 0 pt = 0 sx = 1.0 sy = 1.0
[        ] I/[email protected](13557): aOrMT: [email protected][MainActivity] t = [email protected] fN = 1 android.view.SurfaceView.-$$Nest$mapplyOrMergeTransaction:0
android.view.SurfaceView$SurfaceViewPositionUpdateListener.positionChanged:1537 android.graphics.RenderNode$CompositePositionUpdateListener.positionChanged:373 
[        ] I/[email protected][MainActivity](13557): mWNT: t=0xb400007a48e2b500 mBlastBufferQueue=0xb400007ad227f700 fn= 1 caller= android.view.SurfaceView.applyOrMergeTransaction:1455
android.view.SurfaceView.-$$Nest$mapplyOrMergeTransaction:0 android.view.SurfaceView$SurfaceViewPositionUpdateListener.positionChanged:1537 
[        ] I/[email protected][MainActivity](13557): mWNT: t=0xb400007a48e2b400 mBlastBufferQueue=0xb400007ad227f700 fn= 1 caller= android.view.ViewRootImpl.lambda$applyTransactionOnDraw$11$android-view-ViewRootImpl:12865
android.view.ViewRootImpl$$ExternalSyntheticLambda1.onFrameDraw:4 android.graphics.HardwareRenderer$FrameDrawingCallback.onFrameDraw:924 
[        ] I/[email protected][MainActivity](13557): Received frameDrawingCallback syncResult=0 frameNum=1.
[        ] I/[email protected][MainActivity](13557): Setting up sync and frameCommitCallback
[   +2 ms] I/BLASTBufferQueue(13557): [[email protected][MainActivity]#0](f:0,a:0) onFrameAvailable the first frame is available
[        ] I/[email protected][MainActivity](13557): Received frameCommittedCallback lastAttemptedDrawFrameNum=1 didProduceBuffer=true
[        ] D/OpenGLRenderer(13557): CFMS:: SetUp Pid : 13557    Tid : 13582
[        ] W/Parcel  (13557): Expecting binder but got null!
[        ] I/[email protected][MainActivity](13557): onSyncComplete
[        ] I/[email protected][MainActivity](13557): setupSync seqId=0 mSyncId=0 fn=1 caller=android.view.ViewRootImpl$$ExternalSyntheticLambda11.accept:6
android.window.SurfaceSyncer.lambda$setupSync$1$android-window-SurfaceSyncer:128 android.window.SurfaceSyncer$$ExternalSyntheticLambda1.accept:8 android.window.SurfaceSyncer$SyncSet.checkIfSyncIsComplete:382
android.window.SurfaceSyncer$SyncSet.markSyncReady:359 android.window.SurfaceSyncer.markSyncReady:151 android.view.ViewRootImpl.performTraversals:4503 
[   +2 ms] I/[email protected][MainActivity](13557): reportDrawFinished seqId=0 mSyncId=-1 fn=1 mSurfaceChangedTransaction=0xb400007a48e2b100
[   +4 ms] E/FrameEvents(13557): updateAcquireFence: Did not find frame.
[   +9 ms] I/[email protected][MainActivity](13557): MSG_WINDOW_FOCUS_CHANGED 1 0
[        ] I/[email protected][MainActivity](13557): mThreadedRenderer.initializeIfNeeded()#2 mSurface={isValid=true 0xb400007a2ca7e000}
[   +3 ms] D/InputMethodManager(13557): startInputInner - Id : 0
[        ] I/InputMethodManager(13557): startInputInner - mService.startInputOrWindowGainedFocus
[  +13 ms] D/InputMethodManager(13557): startInputInner - Id : 0
[  +36 ms] E/FrameEvents(13557): updateAcquireFence: Did not find frame.
[        ] D/InsetsController(13557): onStateChanged: InsetsState: {mDisplayFrame=Rect(0, 0 - 1080, 2400), mDisplayCutout=DisplayCutout{insets=Rect(0, 88 - 0, 0) waterfall=Insets{left=0, top=0, right=0, bottom=0}
boundingRect={Bounds=[Rect(0, 0 - 0, 0), Rect(512, 0 - 568, 88), Rect(0, 0 - 0, 0), Rect(0, 0 - 0, 0)]} cutoutPathParserInfo={CutoutPathParserInfo{displayWidth=1080 displayHeight=2400 physicalDisplayWidth=1080
physicalDisplayHeight=2400 density={3.0} cutoutSpec={M 0,0 M 0,10.71963616907435 a 9.280363830925644,9.280363830925644 0 1,0 0,18.56072766185129 a 9.280363830925644,9.280363830925644 0 1,0 0,-18.56072766185129 Z @dp} rotation={0}
scale={1.0} physicalPixelDisplaySizeRatio={1.0}}}}, mRoundedCorners=RoundedCorners{[RoundedCorner{position=TopLeft, radius=96, center=Point(96, 96)}, RoundedCorner{position=TopRight, radius=96, center=Point(984, 96)},
RoundedCorner{position=BottomRight, radius=96, center=Point(984, 2304)}, RoundedCorner{position=BottomLeft, radius=96, center=Point(96, 2304)}]}  mRoundedCornerFrame=Rect(0, 0 - 1080, 2400),
mPrivacyIndicatorBounds=PrivacyIndicatorBounds {static bounds=Rect(948, 0 - 1080, 88) rotation=0}, mSources= { InsetsSource: {mType=ITYPE_STATUS_BAR, mFrame=[0,0][1080,88], mVisible=true, mInsetsRoundedCornerFrame=false},
InsetsSource: {mType=ITYPE_NAVIGATION_BAR, mFrame=[0,2256][1080,2400], mVisible=true, mInsetsRoundedCornerFrame=false}, InsetsSource: {mType=ITYPE_LEFT_GESTURES, mFrame=[0,0][0,2400], mVisible=true, mInsetsRoundedCornerFrame=false},
InsetsSource: {mType=ITYPE_RIGHT_GESTURES, mFrame=[1080,0][1080,2400], mVisible=true, mInsetsRoundedCornerFrame=false}, InsetsSource: {mType=ITYPE_TOP_MANDATORY_GESTURES, mFrame=[0,0][1080,124], mVisible=true,
mInsetsRoundedCornerFrame=false}, InsetsSource: {mType=ITYPE_BOTTOM_MANDATORY_GESTURES, mFrame=[0,2256][1080,2400], mVisible=true, mInsetsRoundedCornerFrame=false}, InsetsSource: {mType=ITYPE_LEFT_DISPLAY_CUTOUT,
mFrame=[0,0][-100000,2400], mVisible=true, mInsetsRoundedCornerFrame=false}, InsetsSource: {mType=ITYPE_TOP_DISPLAY_CUTOUT, mFrame=[0,0][1080,88], mVisible=true, mInsetsRoundedCornerFrame=false}, InsetsSource:
{mType=ITYPE_RIGHT_DISPLAY_CUTOUT, mFrame=[100000,0][1080,2400], mVisible=true, mInsetsRoundedCornerFrame=false}, InsetsSource: {mType=ITYPE_BOTTOM_DISPLAY_CUTOUT, mFrame=[0,100000][1080,2400], mVisible=true,
mInsetsRoundedCornerFrame=false}, InsetsSource: {mType=ITYPE_TOP_TAPPABLE_ELEMENT, mFrame=[0,0][1080,88], mVisible=true, mInsetsRoundedCornerFrame=false}, InsetsSource: {mType=ITYPE_BOTTOM_TAPPABLE_ELEMENT,
mFrame=[0,2256][1080,2400], mVisible=true, mInsetsRoundedCornerFrame=false}, InsetsSource: {mType=ITYPE_IME, mFrame=[0,0][0,0], mVisibleFrame=[0,1374][1080,2400], mVisible=false, mInsetsRoundedCornerFrame=false} }
host=com.example.webview4_ios_bug/com.example.webview4_ios_bug.MainActivity from=android.view.ViewRootImpl$ViewRootHandler.handleMessageImpl:6740
[   +3 ms] E/FrameEvents(13557): updateAcquireFence: Did not find frame.

[βœ“] Flutter (Channel stable, 3.3.9, on macOS 12.6 21G115 darwin-arm, locale en-IL)
    β€’ Flutter version 3.3.9 on channel stable at /Users/lielvdh/Developer/flutter
    β€’ Upstream repository https://github.com/flutter/flutter.git
    β€’ Framework revision b8f7f1f986 (4 months 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/lielvdh/Library/Android/sdk
    β€’ Platform android-33, build-tools 32.1.0-rc1
    β€’ Java binary at: /Applications/Android Studio.app/Contents/jbr/Contents/Home/bin/java
    β€’ Java version OpenJDK Runtime Environment (build 11.0.15+0-b2043.56-8887301)
    β€’ All Android licenses accepted.

[βœ“] Xcode - develop for iOS and macOS (Xcode 14.2)
    β€’ Xcode at /Applications/Xcode.app/Contents/Developer
    β€’ Build 14C18
    β€’ CocoaPods version 1.11.3

[βœ“] Chrome - develop for the web
    β€’ Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[!] Android Studio (version 2022.1)
    β€’ 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
    βœ— Unable to find bundled Java version.
    β€’ Try updating or re-installing Android Studio.

[βœ“] 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 (4 available)
    β€’ SM G781B (mobile)      β€’ RZCT310HAMK               β€’ android-arm64  β€’ Android 13 (API 33)
    β€’ Liel's iPhone (mobile) β€’ 00008030-001631D60CF2802E β€’ ios            β€’ iOS 16.0.2 20A380
    β€’ macOS (desktop)        β€’ macos                     β€’ darwin-arm64   β€’ macOS 12.6 21G115 darwin-arm
    β€’ Chrome (web)           β€’ chrome                    β€’ web-javascript β€’ Google Chrome 111.0.5563.64

[βœ“] HTTP Host Availability
    β€’ All required HTTP hosts are available

! Doctor found issues in 1 category.

LinXunFeng wrote this answer on 2023-03-20

Maybe you should change return NavigationDecision.prevent; to return NavigationDecision.navigate;

I don't understand the logic you wrote in the onNavigationRequest.

huycozy wrote this answer on 2023-03-20

Thanks for filing a detailed issue, @lielvan. Please try @LinXunFeng's suggestion above and check if it's applicable to your case.

lielvan wrote this answer on 2023-03-21

@LinXunFeng
For my use case, I need navigation to a new url path to be handled by the external browser (Chrome app or Safari app), and not by the WebView widget.
Setting return NavigationDecision.navigate does solve the initial loadFile, but ultimately breaks my need to use the external browser app for future navigation requests.

I could implement a workaround by using a bool flag for the initial file load to accept the initial file navigation request on iOS like so:

...
bool _initialWebviewLoad = true;
...
          onNavigationRequest: (navigation) {
            debugPrint('NAVIGATING TO ${navigation.url}');
            if (_initialWebviewLoad && Platform.isIOS) {
              _initialWebviewLoad = false;
              return NavigationDecision.navigate;
            }

            if (navigation.url == 'about:blank') {
              return NavigationDecision.navigate;
            } else {
              launchUrlString(navigation.url, mode: LaunchMode.externalApplication);
              return NavigationDecision.prevent;
            }

but that to me, is certainly not the expected behavior and is a breaking change that worked fine with versions < 4.

LinXunFeng wrote this answer on 2023-03-21

After testing, onNavigationRequest has not been called in Android. This may be an Android problem, not iOS.

If you want to navigate the request for file load, you can make the following adjustments on the code instead of _initialWebviewLoad && Platform.isIOS

if (navigation.url == 'about:blank' || navigation.url.startsWith('file://')) {
  return NavigationDecision.navigate;
}
huycozy wrote this answer on 2023-03-22

As far as I can see, it works on both Android and iOS with the latest workaround of @LinXunFeng. With regard to the issue of onNavigationRequest is not called on Android, I think it should be filed in a new issue on another case.

@lielvan So, is it safe to close this issue as solved? And would you mind file a new issue as mentioned above?

lielvan wrote this answer on 2023-03-22

@huycozy Yep okay to close :) your help is much appreciated @LinXunFeng.
I will conjure up a new issue regarding the Android misbehavior.

More Details About Repo
Owner Name flutter
Repo Name flutter
Full Name flutter/flutter
Language Dart
Created Date 2015-03-06
Updated Date 2023-03-30
Star Count 151602
Watcher Count 3555
Fork Count 25000
Issue Count 11498

YOU MAY BE INTERESTED

Issue Title Created Date Updated Date