[webview_flutter_wkwebview] Copies iOS implementation of webview_flutter from v4_webview (#6852)

* new ios release

* version bump

* add breaking change change

* update excludes file

* fix lints and add to changelog
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/CHANGELOG.md b/packages/webview_flutter/webview_flutter_wkwebview/CHANGELOG.md
index c0a2ade..f859df5 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/CHANGELOG.md
+++ b/packages/webview_flutter/webview_flutter_wkwebview/CHANGELOG.md
@@ -1,5 +1,8 @@
-## NEXT
+## 3.0.0
 
+* **BREAKING CHANGE** Updates platform implementation to `2.0.0` release of
+  `webview_flutter_platform_interface`. See
+  [webview_flutter](https://pub.dev/packages/webview_flutter/versions/4.0.0) for updated usage.
 * Updates code for `no_leading_underscores_for_local_identifiers` lint.
 
 ## 2.9.5
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/example/integration_test/legacy/webview_flutter_test.dart b/packages/webview_flutter/webview_flutter_wkwebview/example/integration_test/legacy/webview_flutter_test.dart
new file mode 100644
index 0000000..f2bae80
--- /dev/null
+++ b/packages/webview_flutter/webview_flutter_wkwebview/example/integration_test/legacy/webview_flutter_test.dart
@@ -0,0 +1,1311 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This test is run using `flutter drive` by the CI (see /script/tool/README.md
+// in this repository for details on driving that tooling manually), but can
+// also be run using `flutter test` directly during development.
+
+import 'dart:async';
+import 'dart:convert';
+import 'dart:io';
+// TODO(a14n): remove this import once Flutter 3.1 or later reaches stable (including flutter/flutter#104231)
+// ignore: unnecessary_import
+import 'dart:typed_data';
+
+import 'package:flutter/foundation.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
+import 'package:flutter_test/flutter_test.dart';
+import 'package:integration_test/integration_test.dart';
+import 'package:webview_flutter_platform_interface/src/webview_flutter_platform_interface_legacy.dart';
+import 'package:webview_flutter_wkwebview/src/common/instance_manager.dart';
+import 'package:webview_flutter_wkwebview/src/common/weak_reference_utils.dart';
+import 'package:webview_flutter_wkwebview_example/legacy/navigation_decision.dart';
+import 'package:webview_flutter_wkwebview_example/legacy/navigation_request.dart';
+import 'package:webview_flutter_wkwebview_example/legacy/web_view.dart';
+
+Future<void> main() async {
+  IntegrationTestWidgetsFlutterBinding.ensureInitialized();
+
+  final HttpServer server = await HttpServer.bind(InternetAddress.anyIPv4, 0);
+  server.forEach((HttpRequest request) {
+    if (request.uri.path == '/hello.txt') {
+      request.response.writeln('Hello, world.');
+    } else if (request.uri.path == '/secondary.txt') {
+      request.response.writeln('How are you today?');
+    } else if (request.uri.path == '/headers') {
+      request.response.writeln('${request.headers}');
+    } else if (request.uri.path == '/favicon.ico') {
+      request.response.statusCode = HttpStatus.notFound;
+    } else {
+      fail('unexpected request: ${request.method} ${request.uri}');
+    }
+    request.response.close();
+  });
+  final String prefixUrl = 'http://${server.address.address}:${server.port}';
+  final String primaryUrl = '$prefixUrl/hello.txt';
+  final String secondaryUrl = '$prefixUrl/secondary.txt';
+  final String headersUrl = '$prefixUrl/headers';
+
+  testWidgets('initialUrl', (WidgetTester tester) async {
+    final Completer<WebViewController> controllerCompleter =
+        Completer<WebViewController>();
+    final Completer<void> pageFinishedCompleter = Completer<void>();
+    await tester.pumpWidget(
+      Directionality(
+        textDirection: TextDirection.ltr,
+        child: WebView(
+          key: GlobalKey(),
+          initialUrl: primaryUrl,
+          onWebViewCreated: (WebViewController controller) {
+            controllerCompleter.complete(controller);
+          },
+          onPageFinished: pageFinishedCompleter.complete,
+        ),
+      ),
+    );
+
+    final WebViewController controller = await controllerCompleter.future;
+    await pageFinishedCompleter.future;
+
+    final String? currentUrl = await controller.currentUrl();
+    expect(currentUrl, primaryUrl);
+  });
+
+  testWidgets(
+      'withWeakRefenceTo allows encapsulating class to be garbage collected',
+      (WidgetTester tester) async {
+    final Completer<int> gcCompleter = Completer<int>();
+    final InstanceManager instanceManager = InstanceManager(
+      onWeakReferenceRemoved: gcCompleter.complete,
+    );
+
+    ClassWithCallbackClass? instance = ClassWithCallbackClass();
+    instanceManager.addHostCreatedInstance(instance.callbackClass, 0);
+    instance = null;
+
+    // Force garbage collection.
+    await IntegrationTestWidgetsFlutterBinding.instance
+        .watchPerformance(() async {
+      await tester.pumpAndSettle();
+    });
+
+    final int gcIdentifier = await gcCompleter.future;
+    expect(gcIdentifier, 0);
+  }, timeout: const Timeout(Duration(seconds: 10)));
+
+  testWidgets('loadUrl', (WidgetTester tester) async {
+    final Completer<WebViewController> controllerCompleter =
+        Completer<WebViewController>();
+    final StreamController<String> pageLoads = StreamController<String>();
+    await tester.pumpWidget(
+      Directionality(
+        textDirection: TextDirection.ltr,
+        child: WebView(
+          key: GlobalKey(),
+          initialUrl: primaryUrl,
+          onWebViewCreated: (WebViewController controller) {
+            controllerCompleter.complete(controller);
+          },
+          onPageFinished: (String url) {
+            pageLoads.add(url);
+          },
+        ),
+      ),
+    );
+    final WebViewController controller = await controllerCompleter.future;
+
+    await controller.loadUrl(secondaryUrl);
+    await expectLater(
+      pageLoads.stream.firstWhere((String url) => url == secondaryUrl),
+      completion(secondaryUrl),
+    );
+  });
+
+  testWidgets('evaluateJavascript', (WidgetTester tester) async {
+    final Completer<WebViewController> controllerCompleter =
+        Completer<WebViewController>();
+    await tester.pumpWidget(
+      Directionality(
+        textDirection: TextDirection.ltr,
+        child: WebView(
+          key: GlobalKey(),
+          initialUrl: primaryUrl,
+          onWebViewCreated: (WebViewController controller) {
+            controllerCompleter.complete(controller);
+          },
+          javascriptMode: JavascriptMode.unrestricted,
+        ),
+      ),
+    );
+    final WebViewController controller = await controllerCompleter.future;
+    final String result = await controller.evaluateJavascript('1 + 1');
+    expect(result, equals('2'));
+  });
+
+  testWidgets('loadUrl with headers', (WidgetTester tester) async {
+    final Completer<WebViewController> controllerCompleter =
+        Completer<WebViewController>();
+    final StreamController<String> pageStarts = StreamController<String>();
+    final StreamController<String> pageLoads = StreamController<String>();
+    await tester.pumpWidget(
+      Directionality(
+        textDirection: TextDirection.ltr,
+        child: WebView(
+          key: GlobalKey(),
+          initialUrl: primaryUrl,
+          onWebViewCreated: (WebViewController controller) {
+            controllerCompleter.complete(controller);
+          },
+          javascriptMode: JavascriptMode.unrestricted,
+          onPageStarted: (String url) {
+            pageStarts.add(url);
+          },
+          onPageFinished: (String url) {
+            pageLoads.add(url);
+          },
+        ),
+      ),
+    );
+    final WebViewController controller = await controllerCompleter.future;
+    final Map<String, String> headers = <String, String>{
+      'test_header': 'flutter_test_header'
+    };
+    await controller.loadUrl(headersUrl, headers: headers);
+    final String? currentUrl = await controller.currentUrl();
+    expect(currentUrl, headersUrl);
+
+    await pageStarts.stream.firstWhere((String url) => url == currentUrl);
+    await pageLoads.stream.firstWhere((String url) => url == currentUrl);
+
+    final String content = await controller
+        .runJavascriptReturningResult('document.documentElement.innerText');
+    expect(content.contains('flutter_test_header'), isTrue);
+  });
+
+  testWidgets('JavascriptChannel', (WidgetTester tester) async {
+    final Completer<WebViewController> controllerCompleter =
+        Completer<WebViewController>();
+    final Completer<void> pageStarted = Completer<void>();
+    final Completer<void> pageLoaded = Completer<void>();
+    final Completer<String> channelCompleter = Completer<String>();
+    await tester.pumpWidget(
+      Directionality(
+        textDirection: TextDirection.ltr,
+        child: WebView(
+          key: GlobalKey(),
+          // This is the data URL for: '<!DOCTYPE html>'
+          initialUrl:
+              'data:text/html;charset=utf-8;base64,PCFET0NUWVBFIGh0bWw+',
+          onWebViewCreated: (WebViewController controller) {
+            controllerCompleter.complete(controller);
+          },
+          javascriptMode: JavascriptMode.unrestricted,
+          javascriptChannels: <JavascriptChannel>{
+            JavascriptChannel(
+              name: 'Echo',
+              onMessageReceived: (JavascriptMessage message) {
+                channelCompleter.complete(message.message);
+              },
+            ),
+          },
+          onPageStarted: (String url) {
+            pageStarted.complete(null);
+          },
+          onPageFinished: (String url) {
+            pageLoaded.complete(null);
+          },
+        ),
+      ),
+    );
+    final WebViewController controller = await controllerCompleter.future;
+    await pageStarted.future;
+    await pageLoaded.future;
+
+    expect(channelCompleter.isCompleted, isFalse);
+    await controller.runJavascript('Echo.postMessage("hello");');
+
+    await expectLater(channelCompleter.future, completion('hello'));
+  });
+
+  testWidgets('resize webview', (WidgetTester tester) async {
+    final Completer<void> buttonTapResizeCompleter = Completer<void>();
+    final Completer<void> onPageFinished = Completer<void>();
+
+    bool resizeButtonTapped = false;
+    await tester.pumpWidget(ResizableWebView(
+      onResize: (_) {
+        if (resizeButtonTapped) {
+          buttonTapResizeCompleter.complete();
+        }
+      },
+      onPageFinished: () => onPageFinished.complete(),
+    ));
+    await onPageFinished.future;
+
+    resizeButtonTapped = true;
+    await tester.tap(find.byKey(const ValueKey<String>('resizeButton')));
+    await tester.pumpAndSettle();
+    expect(buttonTapResizeCompleter.future, completes);
+  });
+
+  testWidgets('set custom userAgent', (WidgetTester tester) async {
+    final Completer<WebViewController> controllerCompleter1 =
+        Completer<WebViewController>();
+    final GlobalKey globalKey = GlobalKey();
+    await tester.pumpWidget(
+      Directionality(
+        textDirection: TextDirection.ltr,
+        child: WebView(
+          key: globalKey,
+          initialUrl: 'about:blank',
+          javascriptMode: JavascriptMode.unrestricted,
+          userAgent: 'Custom_User_Agent1',
+          onWebViewCreated: (WebViewController controller) {
+            controllerCompleter1.complete(controller);
+          },
+        ),
+      ),
+    );
+    final WebViewController controller1 = await controllerCompleter1.future;
+    final String customUserAgent1 = await _getUserAgent(controller1);
+    expect(customUserAgent1, 'Custom_User_Agent1');
+    // rebuild the WebView with a different user agent.
+    await tester.pumpWidget(
+      Directionality(
+        textDirection: TextDirection.ltr,
+        child: WebView(
+          key: globalKey,
+          initialUrl: 'about:blank',
+          javascriptMode: JavascriptMode.unrestricted,
+          userAgent: 'Custom_User_Agent2',
+        ),
+      ),
+    );
+
+    final String customUserAgent2 = await _getUserAgent(controller1);
+    expect(customUserAgent2, 'Custom_User_Agent2');
+  });
+
+  testWidgets('use default platform userAgent after webView is rebuilt',
+      (WidgetTester tester) async {
+    final Completer<WebViewController> controllerCompleter =
+        Completer<WebViewController>();
+    final GlobalKey globalKey = GlobalKey();
+    // Build the webView with no user agent to get the default platform user agent.
+    await tester.pumpWidget(
+      Directionality(
+        textDirection: TextDirection.ltr,
+        child: WebView(
+          key: globalKey,
+          initialUrl: primaryUrl,
+          javascriptMode: JavascriptMode.unrestricted,
+          onWebViewCreated: (WebViewController controller) {
+            controllerCompleter.complete(controller);
+          },
+        ),
+      ),
+    );
+    final WebViewController controller = await controllerCompleter.future;
+    final String defaultPlatformUserAgent = await _getUserAgent(controller);
+    // rebuild the WebView with a custom user agent.
+    await tester.pumpWidget(
+      Directionality(
+        textDirection: TextDirection.ltr,
+        child: WebView(
+          key: globalKey,
+          initialUrl: 'about:blank',
+          javascriptMode: JavascriptMode.unrestricted,
+          userAgent: 'Custom_User_Agent',
+        ),
+      ),
+    );
+    final String customUserAgent = await _getUserAgent(controller);
+    expect(customUserAgent, 'Custom_User_Agent');
+    // rebuilds the WebView with no user agent.
+    await tester.pumpWidget(
+      Directionality(
+        textDirection: TextDirection.ltr,
+        child: WebView(
+          key: globalKey,
+          initialUrl: 'about:blank',
+          javascriptMode: JavascriptMode.unrestricted,
+        ),
+      ),
+    );
+
+    final String customUserAgent2 = await _getUserAgent(controller);
+    expect(customUserAgent2, defaultPlatformUserAgent);
+  });
+
+  group('Video playback policy', () {
+    late String videoTestBase64;
+    setUpAll(() async {
+      final ByteData videoData =
+          await rootBundle.load('assets/sample_video.mp4');
+      final String base64VideoData =
+          base64Encode(Uint8List.view(videoData.buffer));
+      final String videoTest = '''
+        <!DOCTYPE html><html>
+        <head><title>Video auto play</title>
+          <script type="text/javascript">
+            function play() {
+              var video = document.getElementById("video");
+              video.play();
+              video.addEventListener('timeupdate', videoTimeUpdateHandler, false);
+            }
+            function videoTimeUpdateHandler(e) {
+              var video = document.getElementById("video");
+              VideoTestTime.postMessage(video.currentTime);
+            }
+            function isPaused() {
+              var video = document.getElementById("video");
+              return video.paused;
+            }
+            function isFullScreen() {
+              var video = document.getElementById("video");
+              return video.webkitDisplayingFullscreen;
+            }
+          </script>
+        </head>
+        <body onload="play();">
+        <video controls playsinline autoplay id="video">
+          <source src="data:video/mp4;charset=utf-8;base64,$base64VideoData">
+        </video>
+        </body>
+        </html>
+      ''';
+      videoTestBase64 = base64Encode(const Utf8Encoder().convert(videoTest));
+    });
+
+    testWidgets('Auto media playback', (WidgetTester tester) async {
+      Completer<WebViewController> controllerCompleter =
+          Completer<WebViewController>();
+      Completer<void> pageLoaded = Completer<void>();
+
+      await tester.pumpWidget(
+        Directionality(
+          textDirection: TextDirection.ltr,
+          child: WebView(
+            key: GlobalKey(),
+            initialUrl: 'data:text/html;charset=utf-8;base64,$videoTestBase64',
+            onWebViewCreated: (WebViewController controller) {
+              controllerCompleter.complete(controller);
+            },
+            javascriptMode: JavascriptMode.unrestricted,
+            onPageFinished: (String url) {
+              pageLoaded.complete(null);
+            },
+            initialMediaPlaybackPolicy: AutoMediaPlaybackPolicy.always_allow,
+          ),
+        ),
+      );
+      WebViewController controller = await controllerCompleter.future;
+      await pageLoaded.future;
+
+      String isPaused =
+          await controller.runJavascriptReturningResult('isPaused();');
+      expect(isPaused, _webviewBool(false));
+
+      controllerCompleter = Completer<WebViewController>();
+      pageLoaded = Completer<void>();
+
+      // We change the key to re-create a new webview as we change the initialMediaPlaybackPolicy
+      await tester.pumpWidget(
+        Directionality(
+          textDirection: TextDirection.ltr,
+          child: WebView(
+            key: GlobalKey(),
+            initialUrl: 'data:text/html;charset=utf-8;base64,$videoTestBase64',
+            onWebViewCreated: (WebViewController controller) {
+              controllerCompleter.complete(controller);
+            },
+            javascriptMode: JavascriptMode.unrestricted,
+            onPageFinished: (String url) {
+              pageLoaded.complete(null);
+            },
+          ),
+        ),
+      );
+
+      controller = await controllerCompleter.future;
+      await pageLoaded.future;
+
+      isPaused = await controller.runJavascriptReturningResult('isPaused();');
+      expect(isPaused, _webviewBool(true));
+    });
+
+    testWidgets('Changes to initialMediaPlaybackPolicy are ignored',
+        (WidgetTester tester) async {
+      final Completer<WebViewController> controllerCompleter =
+          Completer<WebViewController>();
+      Completer<void> pageLoaded = Completer<void>();
+
+      final GlobalKey key = GlobalKey();
+      await tester.pumpWidget(
+        Directionality(
+          textDirection: TextDirection.ltr,
+          child: WebView(
+            key: key,
+            initialUrl: 'data:text/html;charset=utf-8;base64,$videoTestBase64',
+            onWebViewCreated: (WebViewController controller) {
+              controllerCompleter.complete(controller);
+            },
+            javascriptMode: JavascriptMode.unrestricted,
+            onPageFinished: (String url) {
+              pageLoaded.complete(null);
+            },
+            initialMediaPlaybackPolicy: AutoMediaPlaybackPolicy.always_allow,
+          ),
+        ),
+      );
+      final WebViewController controller = await controllerCompleter.future;
+      await pageLoaded.future;
+
+      String isPaused =
+          await controller.runJavascriptReturningResult('isPaused();');
+      expect(isPaused, _webviewBool(false));
+
+      pageLoaded = Completer<void>();
+
+      await tester.pumpWidget(
+        Directionality(
+          textDirection: TextDirection.ltr,
+          child: WebView(
+            key: key,
+            initialUrl: 'data:text/html;charset=utf-8;base64,$videoTestBase64',
+            onWebViewCreated: (WebViewController controller) {
+              controllerCompleter.complete(controller);
+            },
+            javascriptMode: JavascriptMode.unrestricted,
+            onPageFinished: (String url) {
+              pageLoaded.complete(null);
+            },
+          ),
+        ),
+      );
+
+      await controller.reload();
+
+      await pageLoaded.future;
+
+      isPaused = await controller.runJavascriptReturningResult('isPaused();');
+      expect(isPaused, _webviewBool(false));
+    });
+
+    testWidgets('Video plays inline when allowsInlineMediaPlayback is true',
+        (WidgetTester tester) async {
+      final Completer<WebViewController> controllerCompleter =
+          Completer<WebViewController>();
+      final Completer<void> pageLoaded = Completer<void>();
+      final Completer<void> videoPlaying = Completer<void>();
+
+      await tester.pumpWidget(
+        Directionality(
+          textDirection: TextDirection.ltr,
+          child: WebView(
+            initialUrl: 'data:text/html;charset=utf-8;base64,$videoTestBase64',
+            onWebViewCreated: (WebViewController controller) {
+              controllerCompleter.complete(controller);
+            },
+            javascriptMode: JavascriptMode.unrestricted,
+            javascriptChannels: <JavascriptChannel>{
+              JavascriptChannel(
+                name: 'VideoTestTime',
+                onMessageReceived: (JavascriptMessage message) {
+                  final double currentTime = double.parse(message.message);
+                  // Let it play for at least 1 second to make sure the related video's properties are set.
+                  if (currentTime > 1 && !videoPlaying.isCompleted) {
+                    videoPlaying.complete(null);
+                  }
+                },
+              ),
+            },
+            onPageFinished: (String url) {
+              pageLoaded.complete(null);
+            },
+            initialMediaPlaybackPolicy: AutoMediaPlaybackPolicy.always_allow,
+            allowsInlineMediaPlayback: true,
+          ),
+        ),
+      );
+      final WebViewController controller = await controllerCompleter.future;
+      await pageLoaded.future;
+
+      // Pump once to trigger the video play.
+      await tester.pump();
+
+      // Makes sure we get the correct event that indicates the video is actually playing.
+      await videoPlaying.future;
+
+      final String fullScreen =
+          await controller.runJavascriptReturningResult('isFullScreen();');
+      expect(fullScreen, _webviewBool(false));
+    });
+
+    testWidgets(
+        'Video plays full screen when allowsInlineMediaPlayback is false',
+        (WidgetTester tester) async {
+      final Completer<WebViewController> controllerCompleter =
+          Completer<WebViewController>();
+      final Completer<void> pageLoaded = Completer<void>();
+      final Completer<void> videoPlaying = Completer<void>();
+
+      await tester.pumpWidget(
+        Directionality(
+          textDirection: TextDirection.ltr,
+          child: WebView(
+            initialUrl: 'data:text/html;charset=utf-8;base64,$videoTestBase64',
+            onWebViewCreated: (WebViewController controller) {
+              controllerCompleter.complete(controller);
+            },
+            javascriptMode: JavascriptMode.unrestricted,
+            javascriptChannels: <JavascriptChannel>{
+              JavascriptChannel(
+                name: 'VideoTestTime',
+                onMessageReceived: (JavascriptMessage message) {
+                  final double currentTime = double.parse(message.message);
+                  // Let it play for at least 1 second to make sure the related video's properties are set.
+                  if (currentTime > 1 && !videoPlaying.isCompleted) {
+                    videoPlaying.complete(null);
+                  }
+                },
+              ),
+            },
+            onPageFinished: (String url) {
+              pageLoaded.complete(null);
+            },
+            initialMediaPlaybackPolicy: AutoMediaPlaybackPolicy.always_allow,
+          ),
+        ),
+      );
+      final WebViewController controller = await controllerCompleter.future;
+      await pageLoaded.future;
+
+      // Pump once to trigger the video play.
+      await tester.pump();
+
+      // Makes sure we get the correct event that indicates the video is actually playing.
+      await videoPlaying.future;
+
+      final String fullScreen =
+          await controller.runJavascriptReturningResult('isFullScreen();');
+      expect(fullScreen, _webviewBool(true));
+    });
+  });
+
+  group('Audio playback policy', () {
+    late String audioTestBase64;
+    setUpAll(() async {
+      final ByteData audioData =
+          await rootBundle.load('assets/sample_audio.ogg');
+      final String base64AudioData =
+          base64Encode(Uint8List.view(audioData.buffer));
+      final String audioTest = '''
+        <!DOCTYPE html><html>
+        <head><title>Audio auto play</title>
+          <script type="text/javascript">
+            function play() {
+              var audio = document.getElementById("audio");
+              audio.play();
+            }
+            function isPaused() {
+              var audio = document.getElementById("audio");
+              return audio.paused;
+            }
+          </script>
+        </head>
+        <body onload="play();">
+        <audio controls id="audio">
+          <source src="data:audio/ogg;charset=utf-8;base64,$base64AudioData">
+        </audio>
+        </body>
+        </html>
+      ''';
+      audioTestBase64 = base64Encode(const Utf8Encoder().convert(audioTest));
+    });
+
+    testWidgets('Auto media playback', (WidgetTester tester) async {
+      Completer<WebViewController> controllerCompleter =
+          Completer<WebViewController>();
+      Completer<void> pageStarted = Completer<void>();
+      Completer<void> pageLoaded = Completer<void>();
+
+      await tester.pumpWidget(
+        Directionality(
+          textDirection: TextDirection.ltr,
+          child: WebView(
+            key: GlobalKey(),
+            initialUrl: 'data:text/html;charset=utf-8;base64,$audioTestBase64',
+            onWebViewCreated: (WebViewController controller) {
+              controllerCompleter.complete(controller);
+            },
+            javascriptMode: JavascriptMode.unrestricted,
+            onPageStarted: (String url) {
+              pageStarted.complete(null);
+            },
+            onPageFinished: (String url) {
+              pageLoaded.complete(null);
+            },
+            initialMediaPlaybackPolicy: AutoMediaPlaybackPolicy.always_allow,
+          ),
+        ),
+      );
+      WebViewController controller = await controllerCompleter.future;
+      await pageStarted.future;
+      await pageLoaded.future;
+
+      String isPaused =
+          await controller.runJavascriptReturningResult('isPaused();');
+      expect(isPaused, _webviewBool(false));
+
+      controllerCompleter = Completer<WebViewController>();
+      pageStarted = Completer<void>();
+      pageLoaded = Completer<void>();
+
+      // We change the key to re-create a new webview as we change the initialMediaPlaybackPolicy
+      await tester.pumpWidget(
+        Directionality(
+          textDirection: TextDirection.ltr,
+          child: WebView(
+            key: GlobalKey(),
+            initialUrl: 'data:text/html;charset=utf-8;base64,$audioTestBase64',
+            onWebViewCreated: (WebViewController controller) {
+              controllerCompleter.complete(controller);
+            },
+            javascriptMode: JavascriptMode.unrestricted,
+            onPageStarted: (String url) {
+              pageStarted.complete(null);
+            },
+            onPageFinished: (String url) {
+              pageLoaded.complete(null);
+            },
+          ),
+        ),
+      );
+
+      controller = await controllerCompleter.future;
+      await pageStarted.future;
+      await pageLoaded.future;
+
+      isPaused = await controller.runJavascriptReturningResult('isPaused();');
+      expect(isPaused, _webviewBool(true));
+    });
+
+    testWidgets('Changes to initialMediaPlaybackPolicy are ignored',
+        (WidgetTester tester) async {
+      final Completer<WebViewController> controllerCompleter =
+          Completer<WebViewController>();
+      Completer<void> pageStarted = Completer<void>();
+      Completer<void> pageLoaded = Completer<void>();
+
+      final GlobalKey key = GlobalKey();
+      await tester.pumpWidget(
+        Directionality(
+          textDirection: TextDirection.ltr,
+          child: WebView(
+            key: key,
+            initialUrl: 'data:text/html;charset=utf-8;base64,$audioTestBase64',
+            onWebViewCreated: (WebViewController controller) {
+              controllerCompleter.complete(controller);
+            },
+            javascriptMode: JavascriptMode.unrestricted,
+            onPageStarted: (String url) {
+              pageStarted.complete(null);
+            },
+            onPageFinished: (String url) {
+              pageLoaded.complete(null);
+            },
+            initialMediaPlaybackPolicy: AutoMediaPlaybackPolicy.always_allow,
+          ),
+        ),
+      );
+      final WebViewController controller = await controllerCompleter.future;
+      await pageStarted.future;
+      await pageLoaded.future;
+
+      String isPaused =
+          await controller.runJavascriptReturningResult('isPaused();');
+      expect(isPaused, _webviewBool(false));
+
+      pageStarted = Completer<void>();
+      pageLoaded = Completer<void>();
+
+      await tester.pumpWidget(
+        Directionality(
+          textDirection: TextDirection.ltr,
+          child: WebView(
+            key: key,
+            initialUrl: 'data:text/html;charset=utf-8;base64,$audioTestBase64',
+            onWebViewCreated: (WebViewController controller) {
+              controllerCompleter.complete(controller);
+            },
+            javascriptMode: JavascriptMode.unrestricted,
+            onPageStarted: (String url) {
+              pageStarted.complete(null);
+            },
+            onPageFinished: (String url) {
+              pageLoaded.complete(null);
+            },
+          ),
+        ),
+      );
+
+      await controller.reload();
+
+      await pageStarted.future;
+      await pageLoaded.future;
+
+      isPaused = await controller.runJavascriptReturningResult('isPaused();');
+      expect(isPaused, _webviewBool(false));
+    });
+  });
+
+  testWidgets('getTitle', (WidgetTester tester) async {
+    const String getTitleTest = '''
+        <!DOCTYPE html><html>
+        <head><title>Some title</title>
+        </head>
+        <body>
+        </body>
+        </html>
+      ''';
+    final String getTitleTestBase64 =
+        base64Encode(const Utf8Encoder().convert(getTitleTest));
+    final Completer<void> pageStarted = Completer<void>();
+    final Completer<void> pageLoaded = Completer<void>();
+    final Completer<WebViewController> controllerCompleter =
+        Completer<WebViewController>();
+
+    await tester.pumpWidget(
+      Directionality(
+        textDirection: TextDirection.ltr,
+        child: WebView(
+          initialUrl: 'data:text/html;charset=utf-8;base64,$getTitleTestBase64',
+          javascriptMode: JavascriptMode.unrestricted,
+          onWebViewCreated: (WebViewController controller) {
+            controllerCompleter.complete(controller);
+          },
+          onPageStarted: (String url) {
+            pageStarted.complete(null);
+          },
+          onPageFinished: (String url) {
+            pageLoaded.complete(null);
+          },
+        ),
+      ),
+    );
+
+    final WebViewController controller = await controllerCompleter.future;
+    await pageStarted.future;
+    await pageLoaded.future;
+
+    // On at least iOS, it does not appear to be guaranteed that the native
+    // code has the title when the page load completes. Execute some JavaScript
+    // before checking the title to ensure that the page has been fully parsed
+    // and processed.
+    await controller.runJavascript('1;');
+
+    final String? title = await controller.getTitle();
+    expect(title, 'Some title');
+  });
+
+  group('Programmatic Scroll', () {
+    testWidgets('setAndGetScrollPosition', (WidgetTester tester) async {
+      const String scrollTestPage = '''
+        <!DOCTYPE html>
+        <html>
+          <head>
+            <style>
+              body {
+                height: 100%;
+                width: 100%;
+              }
+              #container{
+                width:5000px;
+                height:5000px;
+            }
+            </style>
+          </head>
+          <body>
+            <div id="container"/>
+          </body>
+        </html>
+      ''';
+
+      final String scrollTestPageBase64 =
+          base64Encode(const Utf8Encoder().convert(scrollTestPage));
+
+      final Completer<void> pageLoaded = Completer<void>();
+      final Completer<WebViewController> controllerCompleter =
+          Completer<WebViewController>();
+
+      await tester.pumpWidget(
+        Directionality(
+          textDirection: TextDirection.ltr,
+          child: WebView(
+            initialUrl:
+                'data:text/html;charset=utf-8;base64,$scrollTestPageBase64',
+            onWebViewCreated: (WebViewController controller) {
+              controllerCompleter.complete(controller);
+            },
+            onPageFinished: (String url) {
+              pageLoaded.complete(null);
+            },
+          ),
+        ),
+      );
+
+      final WebViewController controller = await controllerCompleter.future;
+      await pageLoaded.future;
+
+      await tester.pumpAndSettle(const Duration(seconds: 3));
+
+      int scrollPosX = await controller.getScrollX();
+      int scrollPosY = await controller.getScrollY();
+
+      // Check scrollTo()
+      const int X_SCROLL = 123;
+      const int Y_SCROLL = 321;
+      // Get the initial position; this ensures that scrollTo is actually
+      // changing something, but also gives the native view's scroll position
+      // time to settle.
+      expect(scrollPosX, isNot(X_SCROLL));
+      expect(scrollPosX, isNot(Y_SCROLL));
+
+      await controller.scrollTo(X_SCROLL, Y_SCROLL);
+      scrollPosX = await controller.getScrollX();
+      scrollPosY = await controller.getScrollY();
+      expect(scrollPosX, X_SCROLL);
+      expect(scrollPosY, Y_SCROLL);
+
+      // Check scrollBy() (on top of scrollTo())
+      await controller.scrollBy(X_SCROLL, Y_SCROLL);
+      scrollPosX = await controller.getScrollX();
+      scrollPosY = await controller.getScrollY();
+      expect(scrollPosX, X_SCROLL * 2);
+      expect(scrollPosY, Y_SCROLL * 2);
+    });
+  });
+
+  group('NavigationDelegate', () {
+    const String blankPage = '<!DOCTYPE html><head></head><body></body></html>';
+    final String blankPageEncoded = 'data:text/html;charset=utf-8;base64,'
+        '${base64Encode(const Utf8Encoder().convert(blankPage))}';
+
+    testWidgets('can allow requests', (WidgetTester tester) async {
+      final Completer<WebViewController> controllerCompleter =
+          Completer<WebViewController>();
+      final StreamController<String> pageLoads =
+          StreamController<String>.broadcast();
+      await tester.pumpWidget(
+        Directionality(
+          textDirection: TextDirection.ltr,
+          child: WebView(
+            key: GlobalKey(),
+            initialUrl: blankPageEncoded,
+            onWebViewCreated: (WebViewController controller) {
+              controllerCompleter.complete(controller);
+            },
+            javascriptMode: JavascriptMode.unrestricted,
+            navigationDelegate: (NavigationRequest request) {
+              return (request.url.contains('youtube.com'))
+                  ? NavigationDecision.prevent
+                  : NavigationDecision.navigate;
+            },
+            onPageFinished: (String url) => pageLoads.add(url),
+          ),
+        ),
+      );
+
+      await pageLoads.stream.first; // Wait for initial page load.
+      final WebViewController controller = await controllerCompleter.future;
+      await controller.runJavascript('location.href = "$secondaryUrl"');
+
+      await pageLoads.stream.first; // Wait for the next page load.
+      final String? currentUrl = await controller.currentUrl();
+      expect(currentUrl, secondaryUrl);
+    });
+
+    testWidgets('onWebResourceError', (WidgetTester tester) async {
+      final Completer<WebResourceError> errorCompleter =
+          Completer<WebResourceError>();
+
+      await tester.pumpWidget(
+        Directionality(
+          textDirection: TextDirection.ltr,
+          child: WebView(
+            key: GlobalKey(),
+            initialUrl: 'https://www.notawebsite..com',
+            onWebResourceError: (WebResourceError error) {
+              errorCompleter.complete(error);
+            },
+          ),
+        ),
+      );
+
+      final WebResourceError error = await errorCompleter.future;
+      expect(error, isNotNull);
+
+      if (Platform.isIOS) {
+        expect(error.domain, isNotNull);
+        expect(error.failingUrl, isNull);
+      } else if (Platform.isAndroid) {
+        expect(error.errorType, isNotNull);
+        expect(error.failingUrl?.startsWith('https://www.notawebsite..com'),
+            isTrue);
+      }
+    });
+
+    testWidgets('onWebResourceError is not called with valid url',
+        (WidgetTester tester) async {
+      final Completer<WebResourceError> errorCompleter =
+          Completer<WebResourceError>();
+      final Completer<void> pageFinishCompleter = Completer<void>();
+
+      await tester.pumpWidget(
+        Directionality(
+          textDirection: TextDirection.ltr,
+          child: WebView(
+            key: GlobalKey(),
+            initialUrl:
+                'data:text/html;charset=utf-8;base64,PCFET0NUWVBFIGh0bWw+',
+            onWebResourceError: (WebResourceError error) {
+              errorCompleter.complete(error);
+            },
+            onPageFinished: (_) => pageFinishCompleter.complete(),
+          ),
+        ),
+      );
+
+      expect(errorCompleter.future, doesNotComplete);
+      await pageFinishCompleter.future;
+    });
+
+    testWidgets(
+      'onWebResourceError only called for main frame',
+      (WidgetTester tester) async {
+        const String iframeTest = '''
+        <!DOCTYPE html>
+        <html>
+        <head>
+          <title>WebResourceError test</title>
+        </head>
+        <body>
+          <iframe src="https://notawebsite..com"></iframe>
+        </body>
+        </html>
+       ''';
+        final String iframeTestBase64 =
+            base64Encode(const Utf8Encoder().convert(iframeTest));
+
+        final Completer<WebResourceError> errorCompleter =
+            Completer<WebResourceError>();
+        final Completer<void> pageFinishCompleter = Completer<void>();
+
+        await tester.pumpWidget(
+          Directionality(
+            textDirection: TextDirection.ltr,
+            child: WebView(
+              key: GlobalKey(),
+              initialUrl:
+                  'data:text/html;charset=utf-8;base64,$iframeTestBase64',
+              onWebResourceError: (WebResourceError error) {
+                errorCompleter.complete(error);
+              },
+              onPageFinished: (_) => pageFinishCompleter.complete(),
+            ),
+          ),
+        );
+
+        expect(errorCompleter.future, doesNotComplete);
+        await pageFinishCompleter.future;
+      },
+    );
+
+    testWidgets('can block requests', (WidgetTester tester) async {
+      final Completer<WebViewController> controllerCompleter =
+          Completer<WebViewController>();
+      final StreamController<String> pageLoads =
+          StreamController<String>.broadcast();
+      await tester.pumpWidget(
+        Directionality(
+          textDirection: TextDirection.ltr,
+          child: WebView(
+            key: GlobalKey(),
+            initialUrl: blankPageEncoded,
+            onWebViewCreated: (WebViewController controller) {
+              controllerCompleter.complete(controller);
+            },
+            javascriptMode: JavascriptMode.unrestricted,
+            navigationDelegate: (NavigationRequest request) {
+              return (request.url.contains('youtube.com'))
+                  ? NavigationDecision.prevent
+                  : NavigationDecision.navigate;
+            },
+            onPageFinished: (String url) => pageLoads.add(url),
+          ),
+        ),
+      );
+
+      await pageLoads.stream.first; // Wait for initial page load.
+      final WebViewController controller = await controllerCompleter.future;
+      await controller
+          .runJavascript('location.href = "https://www.youtube.com/"');
+
+      // There should never be any second page load, since our new URL is
+      // blocked. Still wait for a potential page change for some time in order
+      // to give the test a chance to fail.
+      await pageLoads.stream.first
+          .timeout(const Duration(milliseconds: 500), onTimeout: () => '');
+      final String? currentUrl = await controller.currentUrl();
+      expect(currentUrl, isNot(contains('youtube.com')));
+    });
+
+    testWidgets('supports asynchronous decisions', (WidgetTester tester) async {
+      final Completer<WebViewController> controllerCompleter =
+          Completer<WebViewController>();
+      final StreamController<String> pageLoads =
+          StreamController<String>.broadcast();
+      await tester.pumpWidget(
+        Directionality(
+          textDirection: TextDirection.ltr,
+          child: WebView(
+            key: GlobalKey(),
+            initialUrl: blankPageEncoded,
+            onWebViewCreated: (WebViewController controller) {
+              controllerCompleter.complete(controller);
+            },
+            javascriptMode: JavascriptMode.unrestricted,
+            navigationDelegate: (NavigationRequest request) async {
+              NavigationDecision decision = NavigationDecision.prevent;
+              decision = await Future<NavigationDecision>.delayed(
+                  const Duration(milliseconds: 10),
+                  () => NavigationDecision.navigate);
+              return decision;
+            },
+            onPageFinished: (String url) => pageLoads.add(url),
+          ),
+        ),
+      );
+
+      await pageLoads.stream.first; // Wait for initial page load.
+      final WebViewController controller = await controllerCompleter.future;
+      await controller.runJavascript('location.href = "$secondaryUrl"');
+
+      await pageLoads.stream.first; // Wait for second page to load.
+      final String? currentUrl = await controller.currentUrl();
+      expect(currentUrl, secondaryUrl);
+    });
+  });
+
+  testWidgets('launches with gestureNavigationEnabled on iOS',
+      (WidgetTester tester) async {
+    final Completer<WebViewController> controllerCompleter =
+        Completer<WebViewController>();
+    await tester.pumpWidget(
+      Directionality(
+        textDirection: TextDirection.ltr,
+        child: SizedBox(
+          width: 400,
+          height: 300,
+          child: WebView(
+            key: GlobalKey(),
+            initialUrl: primaryUrl,
+            gestureNavigationEnabled: true,
+            onWebViewCreated: (WebViewController controller) {
+              controllerCompleter.complete(controller);
+            },
+          ),
+        ),
+      ),
+    );
+    final WebViewController controller = await controllerCompleter.future;
+    final String? currentUrl = await controller.currentUrl();
+    expect(currentUrl, primaryUrl);
+  });
+
+  testWidgets('target _blank opens in same window',
+      (WidgetTester tester) async {
+    final Completer<WebViewController> controllerCompleter =
+        Completer<WebViewController>();
+    final Completer<void> pageLoaded = Completer<void>();
+    await tester.pumpWidget(
+      Directionality(
+        textDirection: TextDirection.ltr,
+        child: WebView(
+          key: GlobalKey(),
+          onWebViewCreated: (WebViewController controller) {
+            controllerCompleter.complete(controller);
+          },
+          javascriptMode: JavascriptMode.unrestricted,
+          onPageFinished: (String url) {
+            pageLoaded.complete(null);
+          },
+        ),
+      ),
+    );
+    final WebViewController controller = await controllerCompleter.future;
+    await controller.runJavascript('window.open("$primaryUrl", "_blank")');
+    await pageLoaded.future;
+    final String? currentUrl = await controller.currentUrl();
+    expect(currentUrl, primaryUrl);
+  });
+
+  testWidgets(
+    'can open new window and go back',
+    (WidgetTester tester) async {
+      final Completer<WebViewController> controllerCompleter =
+          Completer<WebViewController>();
+      Completer<void> pageLoaded = Completer<void>();
+      await tester.pumpWidget(
+        Directionality(
+          textDirection: TextDirection.ltr,
+          child: WebView(
+            key: GlobalKey(),
+            onWebViewCreated: (WebViewController controller) {
+              controllerCompleter.complete(controller);
+            },
+            javascriptMode: JavascriptMode.unrestricted,
+            onPageFinished: (String url) {
+              pageLoaded.complete();
+            },
+            initialUrl: primaryUrl,
+          ),
+        ),
+      );
+      final WebViewController controller = await controllerCompleter.future;
+      expect(controller.currentUrl(), completion(primaryUrl));
+      await pageLoaded.future;
+      pageLoaded = Completer<void>();
+
+      await controller.runJavascript('window.open("$secondaryUrl")');
+      await pageLoaded.future;
+      pageLoaded = Completer<void>();
+      expect(controller.currentUrl(), completion(secondaryUrl));
+
+      expect(controller.canGoBack(), completion(true));
+      await controller.goBack();
+      await pageLoaded.future;
+      await expectLater(controller.currentUrl(), completion(primaryUrl));
+    },
+  );
+}
+
+// JavaScript booleans evaluate to different string values on Android and iOS.
+// This utility method returns the string boolean value of the current platform.
+String _webviewBool(bool value) {
+  if (defaultTargetPlatform == TargetPlatform.iOS) {
+    return value ? '1' : '0';
+  }
+  return value ? 'true' : 'false';
+}
+
+/// Returns the value used for the HTTP User-Agent: request header in subsequent HTTP requests.
+Future<String> _getUserAgent(WebViewController controller) async {
+  return controller.runJavascriptReturningResult('navigator.userAgent;');
+}
+
+class ResizableWebView extends StatefulWidget {
+  const ResizableWebView(
+      {Key? key, required this.onResize, required this.onPageFinished})
+      : super(key: key);
+
+  final JavascriptMessageHandler onResize;
+  final VoidCallback onPageFinished;
+
+  @override
+  State<StatefulWidget> createState() => ResizableWebViewState();
+}
+
+class ResizableWebViewState extends State<ResizableWebView> {
+  double webViewWidth = 200;
+  double webViewHeight = 200;
+
+  static const String resizePage = '''
+        <!DOCTYPE html><html>
+        <head><title>Resize test</title>
+          <script type="text/javascript">
+            function onResize() {
+              Resize.postMessage("resize");
+            }
+            function onLoad() {
+              window.onresize = onResize;
+            }
+          </script>
+        </head>
+        <body onload="onLoad();" bgColor="blue">
+        </body>
+        </html>
+      ''';
+
+  @override
+  Widget build(BuildContext context) {
+    final String resizeTestBase64 =
+        base64Encode(const Utf8Encoder().convert(resizePage));
+    return Directionality(
+      textDirection: TextDirection.ltr,
+      child: Column(
+        children: <Widget>[
+          SizedBox(
+            width: webViewWidth,
+            height: webViewHeight,
+            child: WebView(
+              initialUrl:
+                  'data:text/html;charset=utf-8;base64,$resizeTestBase64',
+              javascriptChannels: <JavascriptChannel>{
+                JavascriptChannel(
+                  name: 'Resize',
+                  onMessageReceived: widget.onResize,
+                ),
+              },
+              onPageFinished: (_) => widget.onPageFinished(),
+              javascriptMode: JavascriptMode.unrestricted,
+            ),
+          ),
+          TextButton(
+            key: const Key('resizeButton'),
+            onPressed: () {
+              setState(() {
+                webViewWidth += 100.0;
+                webViewHeight += 100.0;
+              });
+            },
+            child: const Text('ResizeButton'),
+          ),
+        ],
+      ),
+    );
+  }
+}
+
+class CopyableObjectWithCallback with Copyable {
+  CopyableObjectWithCallback(this.callback);
+
+  final VoidCallback callback;
+
+  @override
+  CopyableObjectWithCallback copy() {
+    return CopyableObjectWithCallback(callback);
+  }
+}
+
+class ClassWithCallbackClass {
+  ClassWithCallbackClass() {
+    callbackClass = CopyableObjectWithCallback(
+      withWeakRefenceTo(
+        this,
+        (WeakReference<ClassWithCallbackClass> weakReference) {
+          return () {
+            // Weak reference to `this` in callback.
+            // ignore: unnecessary_statements
+            weakReference;
+          };
+        },
+      ),
+    );
+  }
+
+  late final CopyableObjectWithCallback callbackClass;
+}
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/example/integration_test/webview_flutter_test.dart b/packages/webview_flutter/webview_flutter_wkwebview/example/integration_test/webview_flutter_test.dart
index 7e5af0f..946f27b 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/example/integration_test/webview_flutter_test.dart
+++ b/packages/webview_flutter/webview_flutter_wkwebview/example/integration_test/webview_flutter_test.dart
@@ -21,9 +21,7 @@
 import 'package:webview_flutter_platform_interface/webview_flutter_platform_interface.dart';
 import 'package:webview_flutter_wkwebview/src/common/instance_manager.dart';
 import 'package:webview_flutter_wkwebview/src/common/weak_reference_utils.dart';
-import 'package:webview_flutter_wkwebview_example/navigation_decision.dart';
-import 'package:webview_flutter_wkwebview_example/navigation_request.dart';
-import 'package:webview_flutter_wkwebview_example/web_view.dart';
+import 'package:webview_flutter_wkwebview/webview_flutter_wkwebview.dart';
 
 Future<void> main() async {
   IntegrationTestWidgetsFlutterBinding.ensureInitialized();
@@ -48,31 +46,6 @@
   final String secondaryUrl = '$prefixUrl/secondary.txt';
   final String headersUrl = '$prefixUrl/headers';
 
-  testWidgets('initialUrl', (WidgetTester tester) async {
-    final Completer<WebViewController> controllerCompleter =
-        Completer<WebViewController>();
-    final Completer<void> pageFinishedCompleter = Completer<void>();
-    await tester.pumpWidget(
-      Directionality(
-        textDirection: TextDirection.ltr,
-        child: WebView(
-          key: GlobalKey(),
-          initialUrl: primaryUrl,
-          onWebViewCreated: (WebViewController controller) {
-            controllerCompleter.complete(controller);
-          },
-          onPageFinished: pageFinishedCompleter.complete,
-        ),
-      ),
-    );
-
-    final WebViewController controller = await controllerCompleter.future;
-    await pageFinishedCompleter.future;
-
-    final String? currentUrl = await controller.currentUrl();
-    expect(currentUrl, primaryUrl);
-  });
-
   testWidgets(
       'withWeakRefenceTo allows encapsulating class to be garbage collected',
       (WidgetTester tester) async {
@@ -95,137 +68,88 @@
     expect(gcIdentifier, 0);
   }, timeout: const Timeout(Duration(seconds: 10)));
 
-  testWidgets('loadUrl', (WidgetTester tester) async {
-    final Completer<WebViewController> controllerCompleter =
-        Completer<WebViewController>();
-    final StreamController<String> pageLoads = StreamController<String>();
-    await tester.pumpWidget(
-      Directionality(
-        textDirection: TextDirection.ltr,
-        child: WebView(
-          key: GlobalKey(),
-          initialUrl: primaryUrl,
-          onWebViewCreated: (WebViewController controller) {
-            controllerCompleter.complete(controller);
-          },
-          onPageFinished: (String url) {
-            pageLoads.add(url);
-          },
-        ),
-      ),
+  testWidgets('loadRequest', (WidgetTester tester) async {
+    final PlatformWebViewController controller = PlatformWebViewController(
+      const PlatformWebViewControllerCreationParams(),
     );
-    final WebViewController controller = await controllerCompleter.future;
+    controller.loadRequest(LoadRequestParams(uri: Uri.parse(primaryUrl)));
 
-    await controller.loadUrl(secondaryUrl);
+    final String? currentUrl = await controller.currentUrl();
+    expect(currentUrl, primaryUrl);
+  });
+
+  testWidgets('runJavaScriptReturningResult', (WidgetTester tester) async {
+    final PlatformWebViewController controller = PlatformWebViewController(
+      const PlatformWebViewControllerCreationParams(),
+    );
+    controller.loadRequest(LoadRequestParams(uri: Uri.parse(primaryUrl)));
+
     await expectLater(
-      pageLoads.stream.firstWhere((String url) => url == secondaryUrl),
-      completion(secondaryUrl),
+      controller.runJavaScriptReturningResult('1 + 1'),
+      completion(2),
     );
   });
 
-  testWidgets('evaluateJavascript', (WidgetTester tester) async {
-    final Completer<WebViewController> controllerCompleter =
-        Completer<WebViewController>();
-    await tester.pumpWidget(
-      Directionality(
-        textDirection: TextDirection.ltr,
-        child: WebView(
-          key: GlobalKey(),
-          initialUrl: primaryUrl,
-          onWebViewCreated: (WebViewController controller) {
-            controllerCompleter.complete(controller);
-          },
-          javascriptMode: JavascriptMode.unrestricted,
-        ),
-      ),
-    );
-    final WebViewController controller = await controllerCompleter.future;
-    final String result = await controller.evaluateJavascript('1 + 1');
-    expect(result, equals('2'));
-  });
-
-  testWidgets('loadUrl with headers', (WidgetTester tester) async {
-    final Completer<WebViewController> controllerCompleter =
-        Completer<WebViewController>();
-    final StreamController<String> pageStarts = StreamController<String>();
-    final StreamController<String> pageLoads = StreamController<String>();
-    await tester.pumpWidget(
-      Directionality(
-        textDirection: TextDirection.ltr,
-        child: WebView(
-          key: GlobalKey(),
-          initialUrl: primaryUrl,
-          onWebViewCreated: (WebViewController controller) {
-            controllerCompleter.complete(controller);
-          },
-          javascriptMode: JavascriptMode.unrestricted,
-          onPageStarted: (String url) {
-            pageStarts.add(url);
-          },
-          onPageFinished: (String url) {
-            pageLoads.add(url);
-          },
-        ),
-      ),
-    );
-    final WebViewController controller = await controllerCompleter.future;
+  testWidgets('loadRequest with headers', (WidgetTester tester) async {
     final Map<String, String> headers = <String, String>{
       'test_header': 'flutter_test_header'
     };
-    await controller.loadUrl(headersUrl, headers: headers);
-    final String? currentUrl = await controller.currentUrl();
-    expect(currentUrl, headersUrl);
 
-    await pageStarts.stream.firstWhere((String url) => url == currentUrl);
-    await pageLoads.stream.firstWhere((String url) => url == currentUrl);
+    final StreamController<String> pageLoads = StreamController<String>();
 
-    final String content = await controller
-        .runJavascriptReturningResult('document.documentElement.innerText');
+    final PlatformWebViewController controller = PlatformWebViewController(
+      const PlatformWebViewControllerCreationParams(),
+    )
+      ..setJavaScriptMode(JavaScriptMode.unrestricted)
+      ..setPlatformNavigationDelegate(
+        WebKitNavigationDelegate(
+          const WebKitNavigationDelegateCreationParams(),
+        )..setOnPageFinished((String url) => pageLoads.add(url)),
+      )
+      ..loadRequest(
+        LoadRequestParams(
+          uri: Uri.parse(headersUrl),
+          headers: headers,
+        ),
+      );
+
+    await pageLoads.stream.firstWhere((String url) => url == headersUrl);
+
+    final String content = await controller.runJavaScriptReturningResult(
+      'document.documentElement.innerText',
+    ) as String;
     expect(content.contains('flutter_test_header'), isTrue);
   });
 
   testWidgets('JavascriptChannel', (WidgetTester tester) async {
-    final Completer<WebViewController> controllerCompleter =
-        Completer<WebViewController>();
-    final Completer<void> pageStarted = Completer<void>();
-    final Completer<void> pageLoaded = Completer<void>();
+    final Completer<void> pageFinished = Completer<void>();
+    final PlatformWebViewController controller = PlatformWebViewController(
+      const PlatformWebViewControllerCreationParams(),
+    )
+      ..setJavaScriptMode(JavaScriptMode.unrestricted)
+      ..setPlatformNavigationDelegate(
+        WebKitNavigationDelegate(
+          const WebKitNavigationDelegateCreationParams(),
+        )..setOnPageFinished((_) => pageFinished.complete()),
+      );
+
     final Completer<String> channelCompleter = Completer<String>();
-    await tester.pumpWidget(
-      Directionality(
-        textDirection: TextDirection.ltr,
-        child: WebView(
-          key: GlobalKey(),
-          // This is the data URL for: '<!DOCTYPE html>'
-          initialUrl:
-              'data:text/html;charset=utf-8;base64,PCFET0NUWVBFIGh0bWw+',
-          onWebViewCreated: (WebViewController controller) {
-            controllerCompleter.complete(controller);
-          },
-          javascriptMode: JavascriptMode.unrestricted,
-          javascriptChannels: <JavascriptChannel>{
-            JavascriptChannel(
-              name: 'Echo',
-              onMessageReceived: (JavascriptMessage message) {
-                channelCompleter.complete(message.message);
-              },
-            ),
-          },
-          onPageStarted: (String url) {
-            pageStarted.complete(null);
-          },
-          onPageFinished: (String url) {
-            pageLoaded.complete(null);
-          },
-        ),
+    await controller.addJavaScriptChannel(
+      JavaScriptChannelParams(
+        name: 'Echo',
+        onMessageReceived: (JavaScriptMessage message) {
+          channelCompleter.complete(message.message);
+        },
       ),
     );
-    final WebViewController controller = await controllerCompleter.future;
-    await pageStarted.future;
-    await pageLoaded.future;
 
-    expect(channelCompleter.isCompleted, isFalse);
-    await controller.runJavascript('Echo.postMessage("hello");');
+    controller.loadHtmlString(
+      'data:text/html;charset=utf-8;base64,PCFET0NUWVBFIGh0bWw+',
+    );
 
+    await pageFinished.future;
+
+    await controller.runJavaScript('Echo.postMessage("hello");');
     await expectLater(channelCompleter.future, completion('hello'));
   });
 
@@ -235,108 +159,33 @@
 
     bool resizeButtonTapped = false;
     await tester.pumpWidget(ResizableWebView(
-      onResize: (_) {
+      onResize: () {
         if (resizeButtonTapped) {
           buttonTapResizeCompleter.complete();
         }
       },
       onPageFinished: () => onPageFinished.complete(),
     ));
+
     await onPageFinished.future;
 
     resizeButtonTapped = true;
+
     await tester.tap(find.byKey(const ValueKey<String>('resizeButton')));
     await tester.pumpAndSettle();
-    expect(buttonTapResizeCompleter.future, completes);
+
+    await expectLater(buttonTapResizeCompleter.future, completes);
   });
 
   testWidgets('set custom userAgent', (WidgetTester tester) async {
-    final Completer<WebViewController> controllerCompleter1 =
-        Completer<WebViewController>();
-    final GlobalKey globalKey = GlobalKey();
-    await tester.pumpWidget(
-      Directionality(
-        textDirection: TextDirection.ltr,
-        child: WebView(
-          key: globalKey,
-          initialUrl: 'about:blank',
-          javascriptMode: JavascriptMode.unrestricted,
-          userAgent: 'Custom_User_Agent1',
-          onWebViewCreated: (WebViewController controller) {
-            controllerCompleter1.complete(controller);
-          },
-        ),
-      ),
-    );
-    final WebViewController controller1 = await controllerCompleter1.future;
-    final String customUserAgent1 = await _getUserAgent(controller1);
-    expect(customUserAgent1, 'Custom_User_Agent1');
-    // rebuild the WebView with a different user agent.
-    await tester.pumpWidget(
-      Directionality(
-        textDirection: TextDirection.ltr,
-        child: WebView(
-          key: globalKey,
-          initialUrl: 'about:blank',
-          javascriptMode: JavascriptMode.unrestricted,
-          userAgent: 'Custom_User_Agent2',
-        ),
-      ),
-    );
-
-    final String customUserAgent2 = await _getUserAgent(controller1);
-    expect(customUserAgent2, 'Custom_User_Agent2');
-  });
-
-  testWidgets('use default platform userAgent after webView is rebuilt',
-      (WidgetTester tester) async {
-    final Completer<WebViewController> controllerCompleter =
-        Completer<WebViewController>();
-    final GlobalKey globalKey = GlobalKey();
-    // Build the webView with no user agent to get the default platform user agent.
-    await tester.pumpWidget(
-      Directionality(
-        textDirection: TextDirection.ltr,
-        child: WebView(
-          key: globalKey,
-          initialUrl: primaryUrl,
-          javascriptMode: JavascriptMode.unrestricted,
-          onWebViewCreated: (WebViewController controller) {
-            controllerCompleter.complete(controller);
-          },
-        ),
-      ),
-    );
-    final WebViewController controller = await controllerCompleter.future;
-    final String defaultPlatformUserAgent = await _getUserAgent(controller);
-    // rebuild the WebView with a custom user agent.
-    await tester.pumpWidget(
-      Directionality(
-        textDirection: TextDirection.ltr,
-        child: WebView(
-          key: globalKey,
-          initialUrl: 'about:blank',
-          javascriptMode: JavascriptMode.unrestricted,
-          userAgent: 'Custom_User_Agent',
-        ),
-      ),
-    );
-    final String customUserAgent = await _getUserAgent(controller);
-    expect(customUserAgent, 'Custom_User_Agent');
-    // rebuilds the WebView with no user agent.
-    await tester.pumpWidget(
-      Directionality(
-        textDirection: TextDirection.ltr,
-        child: WebView(
-          key: globalKey,
-          initialUrl: 'about:blank',
-          javascriptMode: JavascriptMode.unrestricted,
-        ),
-      ),
-    );
+    final PlatformWebViewController controller = PlatformWebViewController(
+      const PlatformWebViewControllerCreationParams(),
+    )
+      ..setJavaScriptMode(JavaScriptMode.unrestricted)
+      ..setUserAgent('Custom_User_Agent1');
 
     final String customUserAgent2 = await _getUserAgent(controller);
-    expect(customUserAgent2, defaultPlatformUserAgent);
+    expect(customUserAgent2, 'Custom_User_Agent1');
   });
 
   group('Video playback policy', () {
@@ -380,218 +229,168 @@
     });
 
     testWidgets('Auto media playback', (WidgetTester tester) async {
-      Completer<WebViewController> controllerCompleter =
-          Completer<WebViewController>();
       Completer<void> pageLoaded = Completer<void>();
 
-      await tester.pumpWidget(
-        Directionality(
-          textDirection: TextDirection.ltr,
-          child: WebView(
-            key: GlobalKey(),
-            initialUrl: 'data:text/html;charset=utf-8;base64,$videoTestBase64',
-            onWebViewCreated: (WebViewController controller) {
-              controllerCompleter.complete(controller);
-            },
-            javascriptMode: JavascriptMode.unrestricted,
-            onPageFinished: (String url) {
-              pageLoaded.complete(null);
-            },
-            initialMediaPlaybackPolicy: AutoMediaPlaybackPolicy.always_allow,
-          ),
+      PlatformWebViewController controller = PlatformWebViewController(
+        WebKitWebViewControllerCreationParams(
+          mediaTypesRequiringUserAction: const <PlaybackMediaTypes>{},
         ),
-      );
-      WebViewController controller = await controllerCompleter.future;
+      )
+        ..setJavaScriptMode(JavaScriptMode.unrestricted)
+        ..setPlatformNavigationDelegate(
+          WebKitNavigationDelegate(
+            const WebKitNavigationDelegateCreationParams(),
+          )..setOnPageFinished((_) => pageLoaded.complete()),
+        )
+        ..loadRequest(
+          LoadRequestParams(
+            uri: Uri.parse(
+              'data:text/html;charset=utf-8;base64,$videoTestBase64',
+            ),
+          ),
+        );
+
       await pageLoaded.future;
 
-      String isPaused =
-          await controller.runJavascriptReturningResult('isPaused();');
-      expect(isPaused, _webviewBool(false));
-
-      controllerCompleter = Completer<WebViewController>();
-      pageLoaded = Completer<void>();
-
-      // We change the key to re-create a new webview as we change the initialMediaPlaybackPolicy
-      await tester.pumpWidget(
-        Directionality(
-          textDirection: TextDirection.ltr,
-          child: WebView(
-            key: GlobalKey(),
-            initialUrl: 'data:text/html;charset=utf-8;base64,$videoTestBase64',
-            onWebViewCreated: (WebViewController controller) {
-              controllerCompleter.complete(controller);
-            },
-            javascriptMode: JavascriptMode.unrestricted,
-            onPageFinished: (String url) {
-              pageLoaded.complete(null);
-            },
-          ),
-        ),
-      );
-
-      controller = await controllerCompleter.future;
-      await pageLoaded.future;
-
-      isPaused = await controller.runJavascriptReturningResult('isPaused();');
-      expect(isPaused, _webviewBool(true));
-    });
-
-    testWidgets('Changes to initialMediaPlaybackPolicy are ignored',
-        (WidgetTester tester) async {
-      final Completer<WebViewController> controllerCompleter =
-          Completer<WebViewController>();
-      Completer<void> pageLoaded = Completer<void>();
-
-      final GlobalKey key = GlobalKey();
-      await tester.pumpWidget(
-        Directionality(
-          textDirection: TextDirection.ltr,
-          child: WebView(
-            key: key,
-            initialUrl: 'data:text/html;charset=utf-8;base64,$videoTestBase64',
-            onWebViewCreated: (WebViewController controller) {
-              controllerCompleter.complete(controller);
-            },
-            javascriptMode: JavascriptMode.unrestricted,
-            onPageFinished: (String url) {
-              pageLoaded.complete(null);
-            },
-            initialMediaPlaybackPolicy: AutoMediaPlaybackPolicy.always_allow,
-          ),
-        ),
-      );
-      final WebViewController controller = await controllerCompleter.future;
-      await pageLoaded.future;
-
-      String isPaused =
-          await controller.runJavascriptReturningResult('isPaused();');
-      expect(isPaused, _webviewBool(false));
+      bool isPaused =
+          await controller.runJavaScriptReturningResult('isPaused();') as bool;
+      expect(isPaused, false);
 
       pageLoaded = Completer<void>();
-
-      await tester.pumpWidget(
-        Directionality(
-          textDirection: TextDirection.ltr,
-          child: WebView(
-            key: key,
-            initialUrl: 'data:text/html;charset=utf-8;base64,$videoTestBase64',
-            onWebViewCreated: (WebViewController controller) {
-              controllerCompleter.complete(controller);
-            },
-            javascriptMode: JavascriptMode.unrestricted,
-            onPageFinished: (String url) {
-              pageLoaded.complete(null);
-            },
+      controller = PlatformWebViewController(
+        WebKitWebViewControllerCreationParams(),
+      )
+        ..setJavaScriptMode(JavaScriptMode.unrestricted)
+        ..setPlatformNavigationDelegate(
+          WebKitNavigationDelegate(
+            const WebKitNavigationDelegateCreationParams(),
+          )..setOnPageFinished((_) => pageLoaded.complete()),
+        )
+        ..loadRequest(
+          LoadRequestParams(
+            uri: Uri.parse(
+              'data:text/html;charset=utf-8;base64,$videoTestBase64',
+            ),
           ),
-        ),
-      );
-
-      await controller.reload();
+        );
 
       await pageLoaded.future;
 
-      isPaused = await controller.runJavascriptReturningResult('isPaused();');
-      expect(isPaused, _webviewBool(false));
+      isPaused =
+          await controller.runJavaScriptReturningResult('isPaused();') as bool;
+      expect(isPaused, true);
     });
 
     testWidgets('Video plays inline when allowsInlineMediaPlayback is true',
         (WidgetTester tester) async {
-      final Completer<WebViewController> controllerCompleter =
-          Completer<WebViewController>();
       final Completer<void> pageLoaded = Completer<void>();
       final Completer<void> videoPlaying = Completer<void>();
 
-      await tester.pumpWidget(
-        Directionality(
-          textDirection: TextDirection.ltr,
-          child: WebView(
-            initialUrl: 'data:text/html;charset=utf-8;base64,$videoTestBase64',
-            onWebViewCreated: (WebViewController controller) {
-              controllerCompleter.complete(controller);
-            },
-            javascriptMode: JavascriptMode.unrestricted,
-            javascriptChannels: <JavascriptChannel>{
-              JavascriptChannel(
-                name: 'VideoTestTime',
-                onMessageReceived: (JavascriptMessage message) {
-                  final double currentTime = double.parse(message.message);
-                  // Let it play for at least 1 second to make sure the related video's properties are set.
-                  if (currentTime > 1 && !videoPlaying.isCompleted) {
-                    videoPlaying.complete(null);
-                  }
-                },
-              ),
-            },
-            onPageFinished: (String url) {
-              pageLoaded.complete(null);
-            },
-            initialMediaPlaybackPolicy: AutoMediaPlaybackPolicy.always_allow,
-            allowsInlineMediaPlayback: true,
-          ),
+      final PlatformWebViewController controller = PlatformWebViewController(
+        WebKitWebViewControllerCreationParams(
+          mediaTypesRequiringUserAction: const <PlaybackMediaTypes>{},
+          allowsInlineMediaPlayback: true,
         ),
-      );
-      final WebViewController controller = await controllerCompleter.future;
-      await pageLoaded.future;
+      )
+        ..setJavaScriptMode(JavaScriptMode.unrestricted)
+        ..setPlatformNavigationDelegate(
+          WebKitNavigationDelegate(
+            const WebKitNavigationDelegateCreationParams(),
+          )..setOnPageFinished((_) => pageLoaded.complete()),
+        )
+        ..addJavaScriptChannel(
+          JavaScriptChannelParams(
+            name: 'VideoTestTime',
+            onMessageReceived: (JavaScriptMessage message) {
+              final double currentTime = double.parse(message.message);
+              // Let it play for at least 1 second to make sure the related video's properties are set.
+              if (currentTime > 1 && !videoPlaying.isCompleted) {
+                videoPlaying.complete(null);
+              }
+            },
+          ),
+        )
+        ..loadRequest(
+          LoadRequestParams(
+            uri: Uri.parse(
+              'data:text/html;charset=utf-8;base64,$videoTestBase64',
+            ),
+          ),
+        );
 
-      // Pump once to trigger the video play.
-      await tester.pump();
+      await tester.pumpWidget(Builder(
+        builder: (BuildContext context) {
+          return PlatformWebViewWidget(
+            PlatformWebViewWidgetCreationParams(controller: controller),
+          ).build(context);
+        },
+      ));
+      await tester.pumpAndSettle();
+
+      await pageLoaded.future;
 
       // Makes sure we get the correct event that indicates the video is actually playing.
       await videoPlaying.future;
 
-      final String fullScreen =
-          await controller.runJavascriptReturningResult('isFullScreen();');
-      expect(fullScreen, _webviewBool(false));
+      final bool fullScreen = await controller
+          .runJavaScriptReturningResult('isFullScreen();') as bool;
+      expect(fullScreen, false);
     });
 
     testWidgets(
         'Video plays full screen when allowsInlineMediaPlayback is false',
         (WidgetTester tester) async {
-      final Completer<WebViewController> controllerCompleter =
-          Completer<WebViewController>();
       final Completer<void> pageLoaded = Completer<void>();
       final Completer<void> videoPlaying = Completer<void>();
 
-      await tester.pumpWidget(
-        Directionality(
-          textDirection: TextDirection.ltr,
-          child: WebView(
-            initialUrl: 'data:text/html;charset=utf-8;base64,$videoTestBase64',
-            onWebViewCreated: (WebViewController controller) {
-              controllerCompleter.complete(controller);
-            },
-            javascriptMode: JavascriptMode.unrestricted,
-            javascriptChannels: <JavascriptChannel>{
-              JavascriptChannel(
-                name: 'VideoTestTime',
-                onMessageReceived: (JavascriptMessage message) {
-                  final double currentTime = double.parse(message.message);
-                  // Let it play for at least 1 second to make sure the related video's properties are set.
-                  if (currentTime > 1 && !videoPlaying.isCompleted) {
-                    videoPlaying.complete(null);
-                  }
-                },
-              ),
-            },
-            onPageFinished: (String url) {
-              pageLoaded.complete(null);
-            },
-            initialMediaPlaybackPolicy: AutoMediaPlaybackPolicy.always_allow,
-          ),
+      final PlatformWebViewController controller = PlatformWebViewController(
+        WebKitWebViewControllerCreationParams(
+          mediaTypesRequiringUserAction: const <PlaybackMediaTypes>{},
         ),
-      );
-      final WebViewController controller = await controllerCompleter.future;
-      await pageLoaded.future;
+      )
+        ..setJavaScriptMode(JavaScriptMode.unrestricted)
+        ..setPlatformNavigationDelegate(
+          WebKitNavigationDelegate(
+            const WebKitNavigationDelegateCreationParams(),
+          )..setOnPageFinished((_) => pageLoaded.complete()),
+        )
+        ..addJavaScriptChannel(
+          JavaScriptChannelParams(
+            name: 'VideoTestTime',
+            onMessageReceived: (JavaScriptMessage message) {
+              final double currentTime = double.parse(message.message);
+              // Let it play for at least 1 second to make sure the related video's properties are set.
+              if (currentTime > 1 && !videoPlaying.isCompleted) {
+                videoPlaying.complete(null);
+              }
+            },
+          ),
+        )
+        ..loadRequest(
+          LoadRequestParams(
+            uri: Uri.parse(
+              'data:text/html;charset=utf-8;base64,$videoTestBase64',
+            ),
+          ),
+        );
 
-      // Pump once to trigger the video play.
-      await tester.pump();
+      await tester.pumpWidget(Builder(
+        builder: (BuildContext context) {
+          return PlatformWebViewWidget(
+            PlatformWebViewWidgetCreationParams(controller: controller),
+          ).build(context);
+        },
+      ));
+      await tester.pumpAndSettle();
+
+      await pageLoaded.future;
 
       // Makes sure we get the correct event that indicates the video is actually playing.
       await videoPlaying.future;
 
-      final String fullScreen =
-          await controller.runJavascriptReturningResult('isFullScreen();');
-      expect(fullScreen, _webviewBool(true));
+      final bool fullScreen = await controller
+          .runJavaScriptReturningResult('isFullScreen();') as bool;
+      expect(fullScreen, true);
     });
   });
 
@@ -627,138 +426,56 @@
     });
 
     testWidgets('Auto media playback', (WidgetTester tester) async {
-      Completer<WebViewController> controllerCompleter =
-          Completer<WebViewController>();
-      Completer<void> pageStarted = Completer<void>();
       Completer<void> pageLoaded = Completer<void>();
 
-      await tester.pumpWidget(
-        Directionality(
-          textDirection: TextDirection.ltr,
-          child: WebView(
-            key: GlobalKey(),
-            initialUrl: 'data:text/html;charset=utf-8;base64,$audioTestBase64',
-            onWebViewCreated: (WebViewController controller) {
-              controllerCompleter.complete(controller);
-            },
-            javascriptMode: JavascriptMode.unrestricted,
-            onPageStarted: (String url) {
-              pageStarted.complete(null);
-            },
-            onPageFinished: (String url) {
-              pageLoaded.complete(null);
-            },
-            initialMediaPlaybackPolicy: AutoMediaPlaybackPolicy.always_allow,
-          ),
+      PlatformWebViewController controller = PlatformWebViewController(
+        WebKitWebViewControllerCreationParams(
+          mediaTypesRequiringUserAction: const <PlaybackMediaTypes>{},
         ),
-      );
-      WebViewController controller = await controllerCompleter.future;
-      await pageStarted.future;
+      )
+        ..setJavaScriptMode(JavaScriptMode.unrestricted)
+        ..setPlatformNavigationDelegate(
+          WebKitNavigationDelegate(
+            const WebKitNavigationDelegateCreationParams(),
+          )..setOnPageFinished((_) => pageLoaded.complete()),
+        )
+        ..loadRequest(
+          LoadRequestParams(
+            uri: Uri.parse(
+              'data:text/html;charset=utf-8;base64,$audioTestBase64',
+            ),
+          ),
+        );
+
       await pageLoaded.future;
 
-      String isPaused =
-          await controller.runJavascriptReturningResult('isPaused();');
-      expect(isPaused, _webviewBool(false));
+      bool isPaused =
+          await controller.runJavaScriptReturningResult('isPaused();') as bool;
+      expect(isPaused, false);
 
-      controllerCompleter = Completer<WebViewController>();
-      pageStarted = Completer<void>();
       pageLoaded = Completer<void>();
-
-      // We change the key to re-create a new webview as we change the initialMediaPlaybackPolicy
-      await tester.pumpWidget(
-        Directionality(
-          textDirection: TextDirection.ltr,
-          child: WebView(
-            key: GlobalKey(),
-            initialUrl: 'data:text/html;charset=utf-8;base64,$audioTestBase64',
-            onWebViewCreated: (WebViewController controller) {
-              controllerCompleter.complete(controller);
-            },
-            javascriptMode: JavascriptMode.unrestricted,
-            onPageStarted: (String url) {
-              pageStarted.complete(null);
-            },
-            onPageFinished: (String url) {
-              pageLoaded.complete(null);
-            },
+      controller = PlatformWebViewController(
+        WebKitWebViewControllerCreationParams(),
+      )
+        ..setJavaScriptMode(JavaScriptMode.unrestricted)
+        ..setPlatformNavigationDelegate(
+          WebKitNavigationDelegate(
+            const WebKitNavigationDelegateCreationParams(),
+          )..setOnPageFinished((_) => pageLoaded.complete()),
+        )
+        ..loadRequest(
+          LoadRequestParams(
+            uri: Uri.parse(
+              'data:text/html;charset=utf-8;base64,$audioTestBase64',
+            ),
           ),
-        ),
-      );
+        );
 
-      controller = await controllerCompleter.future;
-      await pageStarted.future;
       await pageLoaded.future;
 
-      isPaused = await controller.runJavascriptReturningResult('isPaused();');
-      expect(isPaused, _webviewBool(true));
-    });
-
-    testWidgets('Changes to initialMediaPlaybackPolicy are ignored',
-        (WidgetTester tester) async {
-      final Completer<WebViewController> controllerCompleter =
-          Completer<WebViewController>();
-      Completer<void> pageStarted = Completer<void>();
-      Completer<void> pageLoaded = Completer<void>();
-
-      final GlobalKey key = GlobalKey();
-      await tester.pumpWidget(
-        Directionality(
-          textDirection: TextDirection.ltr,
-          child: WebView(
-            key: key,
-            initialUrl: 'data:text/html;charset=utf-8;base64,$audioTestBase64',
-            onWebViewCreated: (WebViewController controller) {
-              controllerCompleter.complete(controller);
-            },
-            javascriptMode: JavascriptMode.unrestricted,
-            onPageStarted: (String url) {
-              pageStarted.complete(null);
-            },
-            onPageFinished: (String url) {
-              pageLoaded.complete(null);
-            },
-            initialMediaPlaybackPolicy: AutoMediaPlaybackPolicy.always_allow,
-          ),
-        ),
-      );
-      final WebViewController controller = await controllerCompleter.future;
-      await pageStarted.future;
-      await pageLoaded.future;
-
-      String isPaused =
-          await controller.runJavascriptReturningResult('isPaused();');
-      expect(isPaused, _webviewBool(false));
-
-      pageStarted = Completer<void>();
-      pageLoaded = Completer<void>();
-
-      await tester.pumpWidget(
-        Directionality(
-          textDirection: TextDirection.ltr,
-          child: WebView(
-            key: key,
-            initialUrl: 'data:text/html;charset=utf-8;base64,$audioTestBase64',
-            onWebViewCreated: (WebViewController controller) {
-              controllerCompleter.complete(controller);
-            },
-            javascriptMode: JavascriptMode.unrestricted,
-            onPageStarted: (String url) {
-              pageStarted.complete(null);
-            },
-            onPageFinished: (String url) {
-              pageLoaded.complete(null);
-            },
-          ),
-        ),
-      );
-
-      await controller.reload();
-
-      await pageStarted.future;
-      await pageLoaded.future;
-
-      isPaused = await controller.runJavascriptReturningResult('isPaused();');
-      expect(isPaused, _webviewBool(false));
+      isPaused =
+          await controller.runJavaScriptReturningResult('isPaused();') as bool;
+      expect(isPaused, true);
     });
   });
 
@@ -773,39 +490,32 @@
       ''';
     final String getTitleTestBase64 =
         base64Encode(const Utf8Encoder().convert(getTitleTest));
-    final Completer<void> pageStarted = Completer<void>();
     final Completer<void> pageLoaded = Completer<void>();
-    final Completer<WebViewController> controllerCompleter =
-        Completer<WebViewController>();
 
-    await tester.pumpWidget(
-      Directionality(
-        textDirection: TextDirection.ltr,
-        child: WebView(
-          initialUrl: 'data:text/html;charset=utf-8;base64,$getTitleTestBase64',
-          javascriptMode: JavascriptMode.unrestricted,
-          onWebViewCreated: (WebViewController controller) {
-            controllerCompleter.complete(controller);
-          },
-          onPageStarted: (String url) {
-            pageStarted.complete(null);
-          },
-          onPageFinished: (String url) {
-            pageLoaded.complete(null);
-          },
+    final PlatformWebViewController controller = PlatformWebViewController(
+      WebKitWebViewControllerCreationParams(),
+    )
+      ..setJavaScriptMode(JavaScriptMode.unrestricted)
+      ..setPlatformNavigationDelegate(
+        WebKitNavigationDelegate(
+          const WebKitNavigationDelegateCreationParams(),
+        )..setOnPageFinished((_) => pageLoaded.complete()),
+      )
+      ..loadRequest(
+        LoadRequestParams(
+          uri: Uri.parse(
+            'data:text/html;charset=utf-8;base64,$getTitleTestBase64',
+          ),
         ),
-      ),
-    );
+      );
 
-    final WebViewController controller = await controllerCompleter.future;
-    await pageStarted.future;
     await pageLoaded.future;
 
     // On at least iOS, it does not appear to be guaranteed that the native
     // code has the title when the page load completes. Execute some JavaScript
     // before checking the title to ensure that the page has been fully parsed
     // and processed.
-    await controller.runJavascript('1;');
+    await controller.runJavaScript('1;');
 
     final String? title = await controller.getTitle();
     expect(title, 'Some title');
@@ -838,32 +548,28 @@
           base64Encode(const Utf8Encoder().convert(scrollTestPage));
 
       final Completer<void> pageLoaded = Completer<void>();
-      final Completer<WebViewController> controllerCompleter =
-          Completer<WebViewController>();
-
-      await tester.pumpWidget(
-        Directionality(
-          textDirection: TextDirection.ltr,
-          child: WebView(
-            initialUrl:
-                'data:text/html;charset=utf-8;base64,$scrollTestPageBase64',
-            onWebViewCreated: (WebViewController controller) {
-              controllerCompleter.complete(controller);
-            },
-            onPageFinished: (String url) {
-              pageLoaded.complete(null);
-            },
+      final PlatformWebViewController controller = PlatformWebViewController(
+        WebKitWebViewControllerCreationParams(),
+      )
+        ..setJavaScriptMode(JavaScriptMode.unrestricted)
+        ..setPlatformNavigationDelegate(
+          WebKitNavigationDelegate(
+            const WebKitNavigationDelegateCreationParams(),
+          )..setOnPageFinished((_) => pageLoaded.complete()),
+        )
+        ..loadRequest(
+          LoadRequestParams(
+            uri: Uri.parse(
+              'data:text/html;charset=utf-8;base64,$scrollTestPageBase64',
+            ),
           ),
-        ),
-      );
+        );
 
-      final WebViewController controller = await controllerCompleter.future;
       await pageLoaded.future;
 
       await tester.pumpAndSettle(const Duration(seconds: 3));
 
-      int scrollPosX = await controller.getScrollX();
-      int scrollPosY = await controller.getScrollY();
+      Offset scrollPos = await controller.getScrollPosition();
 
       // Check scrollTo()
       const int X_SCROLL = 123;
@@ -871,21 +577,19 @@
       // Get the initial position; this ensures that scrollTo is actually
       // changing something, but also gives the native view's scroll position
       // time to settle.
-      expect(scrollPosX, isNot(X_SCROLL));
-      expect(scrollPosX, isNot(Y_SCROLL));
+      expect(scrollPos.dx, isNot(X_SCROLL));
+      expect(scrollPos.dy, isNot(Y_SCROLL));
 
       await controller.scrollTo(X_SCROLL, Y_SCROLL);
-      scrollPosX = await controller.getScrollX();
-      scrollPosY = await controller.getScrollY();
-      expect(scrollPosX, X_SCROLL);
-      expect(scrollPosY, Y_SCROLL);
+      scrollPos = await controller.getScrollPosition();
+      expect(scrollPos.dx, X_SCROLL);
+      expect(scrollPos.dy, Y_SCROLL);
 
       // Check scrollBy() (on top of scrollTo())
       await controller.scrollBy(X_SCROLL, Y_SCROLL);
-      scrollPosX = await controller.getScrollX();
-      scrollPosY = await controller.getScrollY();
-      expect(scrollPosX, X_SCROLL * 2);
-      expect(scrollPosY, Y_SCROLL * 2);
+      scrollPos = await controller.getScrollPosition();
+      expect(scrollPos.dx, X_SCROLL * 2);
+      expect(scrollPos.dy, Y_SCROLL * 2);
     });
   });
 
@@ -895,33 +599,30 @@
         '${base64Encode(const Utf8Encoder().convert(blankPage))}';
 
     testWidgets('can allow requests', (WidgetTester tester) async {
-      final Completer<WebViewController> controllerCompleter =
-          Completer<WebViewController>();
       final StreamController<String> pageLoads =
           StreamController<String>.broadcast();
-      await tester.pumpWidget(
-        Directionality(
-          textDirection: TextDirection.ltr,
-          child: WebView(
-            key: GlobalKey(),
-            initialUrl: blankPageEncoded,
-            onWebViewCreated: (WebViewController controller) {
-              controllerCompleter.complete(controller);
-            },
-            javascriptMode: JavascriptMode.unrestricted,
-            navigationDelegate: (NavigationRequest request) {
-              return (request.url.contains('youtube.com'))
+
+      final PlatformWebViewController controller = PlatformWebViewController(
+        WebKitWebViewControllerCreationParams(),
+      )
+        ..setJavaScriptMode(JavaScriptMode.unrestricted)
+        ..setPlatformNavigationDelegate(
+          WebKitNavigationDelegate(
+            const WebKitNavigationDelegateCreationParams(),
+          )
+            ..setOnPageFinished((String url) => pageLoads.add(url))
+            ..setOnNavigationRequest((NavigationRequest navigationRequest) {
+              return (navigationRequest.url.contains('youtube.com'))
                   ? NavigationDecision.prevent
                   : NavigationDecision.navigate;
-            },
-            onPageFinished: (String url) => pageLoads.add(url),
-          ),
-        ),
-      );
+            }),
+        )
+        ..loadRequest(
+          LoadRequestParams(uri: Uri.parse(blankPageEncoded)),
+        );
 
       await pageLoads.stream.first; // Wait for initial page load.
-      final WebViewController controller = await controllerCompleter.future;
-      await controller.runJavascript('location.href = "$secondaryUrl"');
+      await controller.runJavaScript('location.href = "$secondaryUrl"');
 
       await pageLoads.stream.first; // Wait for the next page load.
       final String? currentUrl = await controller.currentUrl();
@@ -932,30 +633,25 @@
       final Completer<WebResourceError> errorCompleter =
           Completer<WebResourceError>();
 
-      await tester.pumpWidget(
-        Directionality(
-          textDirection: TextDirection.ltr,
-          child: WebView(
-            key: GlobalKey(),
-            initialUrl: 'https://www.notawebsite..com',
-            onWebResourceError: (WebResourceError error) {
+      PlatformWebViewController(
+        WebKitWebViewControllerCreationParams(),
+      )
+        ..setJavaScriptMode(JavaScriptMode.unrestricted)
+        ..setPlatformNavigationDelegate(
+          WebKitNavigationDelegate(
+            const WebKitNavigationDelegateCreationParams(),
+          )..setOnWebResourceError((WebResourceError error) {
               errorCompleter.complete(error);
-            },
-          ),
-        ),
-      );
+            }),
+        )
+        ..loadRequest(
+          LoadRequestParams(uri: Uri.parse('https://www.notawebsite..com')),
+        );
 
       final WebResourceError error = await errorCompleter.future;
       expect(error, isNotNull);
 
-      if (Platform.isIOS) {
-        expect(error.domain, isNotNull);
-        expect(error.failingUrl, isNull);
-      } else if (Platform.isAndroid) {
-        expect(error.errorType, isNotNull);
-        expect(error.failingUrl?.startsWith('https://www.notawebsite..com'),
-            isTrue);
-      }
+      expect((error as WebKitWebResourceError).domain, isNotNull);
     });
 
     testWidgets('onWebResourceError is not called with valid url',
@@ -964,20 +660,26 @@
           Completer<WebResourceError>();
       final Completer<void> pageFinishCompleter = Completer<void>();
 
-      await tester.pumpWidget(
-        Directionality(
-          textDirection: TextDirection.ltr,
-          child: WebView(
-            key: GlobalKey(),
-            initialUrl:
-                'data:text/html;charset=utf-8;base64,PCFET0NUWVBFIGh0bWw+',
-            onWebResourceError: (WebResourceError error) {
+      PlatformWebViewController(
+        WebKitWebViewControllerCreationParams(),
+      )
+        ..setJavaScriptMode(JavaScriptMode.unrestricted)
+        ..setPlatformNavigationDelegate(
+          WebKitNavigationDelegate(
+            const WebKitNavigationDelegateCreationParams(),
+          )
+            ..setOnPageFinished((_) => pageFinishCompleter.complete())
+            ..setOnWebResourceError((WebResourceError error) {
               errorCompleter.complete(error);
-            },
-            onPageFinished: (_) => pageFinishCompleter.complete(),
+            }),
+        )
+        ..loadRequest(
+          LoadRequestParams(
+            uri: Uri.parse(
+              'data:text/html;charset=utf-8;base64,PCFET0NUWVBFIGh0bWw+',
+            ),
           ),
-        ),
-      );
+        );
 
       expect(errorCompleter.future, doesNotComplete);
       await pageFinishCompleter.future;
@@ -987,16 +689,16 @@
       'onWebResourceError only called for main frame',
       (WidgetTester tester) async {
         const String iframeTest = '''
-        <!DOCTYPE html>
-        <html>
-        <head>
-          <title>WebResourceError test</title>
-        </head>
-        <body>
-          <iframe src="https://notawebsite..com"></iframe>
-        </body>
-        </html>
-       ''';
+          <!DOCTYPE html>
+          <html>
+          <head>
+            <title>WebResourceError test</title>
+          </head>
+          <body>
+            <iframe src="https://notawebsite..com"></iframe>
+          </body>
+          </html>
+         ''';
         final String iframeTestBase64 =
             base64Encode(const Utf8Encoder().convert(iframeTest));
 
@@ -1004,20 +706,26 @@
             Completer<WebResourceError>();
         final Completer<void> pageFinishCompleter = Completer<void>();
 
-        await tester.pumpWidget(
-          Directionality(
-            textDirection: TextDirection.ltr,
-            child: WebView(
-              key: GlobalKey(),
-              initialUrl:
-                  'data:text/html;charset=utf-8;base64,$iframeTestBase64',
-              onWebResourceError: (WebResourceError error) {
+        PlatformWebViewController(
+          WebKitWebViewControllerCreationParams(),
+        )
+          ..setJavaScriptMode(JavaScriptMode.unrestricted)
+          ..setPlatformNavigationDelegate(
+            WebKitNavigationDelegate(
+              const WebKitNavigationDelegateCreationParams(),
+            )
+              ..setOnPageFinished((_) => pageFinishCompleter.complete())
+              ..setOnWebResourceError((WebResourceError error) {
                 errorCompleter.complete(error);
-              },
-              onPageFinished: (_) => pageFinishCompleter.complete(),
+              }),
+          )
+          ..loadRequest(
+            LoadRequestParams(
+              uri: Uri.parse(
+                'data:text/html;charset=utf-8;base64,$iframeTestBase64',
+              ),
             ),
-          ),
-        );
+          );
 
         expect(errorCompleter.future, doesNotComplete);
         await pageFinishCompleter.future;
@@ -1025,34 +733,29 @@
     );
 
     testWidgets('can block requests', (WidgetTester tester) async {
-      final Completer<WebViewController> controllerCompleter =
-          Completer<WebViewController>();
       final StreamController<String> pageLoads =
           StreamController<String>.broadcast();
-      await tester.pumpWidget(
-        Directionality(
-          textDirection: TextDirection.ltr,
-          child: WebView(
-            key: GlobalKey(),
-            initialUrl: blankPageEncoded,
-            onWebViewCreated: (WebViewController controller) {
-              controllerCompleter.complete(controller);
-            },
-            javascriptMode: JavascriptMode.unrestricted,
-            navigationDelegate: (NavigationRequest request) {
-              return (request.url.contains('youtube.com'))
+
+      final PlatformWebViewController controller = PlatformWebViewController(
+        WebKitWebViewControllerCreationParams(),
+      )
+        ..setJavaScriptMode(JavaScriptMode.unrestricted)
+        ..setPlatformNavigationDelegate(
+          WebKitNavigationDelegate(
+            const WebKitNavigationDelegateCreationParams(),
+          )
+            ..setOnPageFinished((String url) => pageLoads.add(url))
+            ..setOnNavigationRequest((NavigationRequest navigationRequest) {
+              return (navigationRequest.url.contains('youtube.com'))
                   ? NavigationDecision.prevent
                   : NavigationDecision.navigate;
-            },
-            onPageFinished: (String url) => pageLoads.add(url),
-          ),
-        ),
-      );
+            }),
+        )
+        ..loadRequest(LoadRequestParams(uri: Uri.parse(blankPageEncoded)));
 
       await pageLoads.stream.first; // Wait for initial page load.
-      final WebViewController controller = await controllerCompleter.future;
       await controller
-          .runJavascript('location.href = "https://www.youtube.com/"');
+          .runJavaScript('location.href = "https://www.youtube.com/"');
 
       // There should never be any second page load, since our new URL is
       // blocked. Still wait for a potential page change for some time in order
@@ -1064,35 +767,31 @@
     });
 
     testWidgets('supports asynchronous decisions', (WidgetTester tester) async {
-      final Completer<WebViewController> controllerCompleter =
-          Completer<WebViewController>();
       final StreamController<String> pageLoads =
           StreamController<String>.broadcast();
-      await tester.pumpWidget(
-        Directionality(
-          textDirection: TextDirection.ltr,
-          child: WebView(
-            key: GlobalKey(),
-            initialUrl: blankPageEncoded,
-            onWebViewCreated: (WebViewController controller) {
-              controllerCompleter.complete(controller);
-            },
-            javascriptMode: JavascriptMode.unrestricted,
-            navigationDelegate: (NavigationRequest request) async {
+
+      final PlatformWebViewController controller = PlatformWebViewController(
+        WebKitWebViewControllerCreationParams(),
+      )
+        ..setJavaScriptMode(JavaScriptMode.unrestricted)
+        ..setPlatformNavigationDelegate(
+          WebKitNavigationDelegate(
+            const WebKitNavigationDelegateCreationParams(),
+          )
+            ..setOnPageFinished((String url) => pageLoads.add(url))
+            ..setOnNavigationRequest(
+                (NavigationRequest navigationRequest) async {
               NavigationDecision decision = NavigationDecision.prevent;
               decision = await Future<NavigationDecision>.delayed(
                   const Duration(milliseconds: 10),
                   () => NavigationDecision.navigate);
               return decision;
-            },
-            onPageFinished: (String url) => pageLoads.add(url),
-          ),
-        ),
-      );
+            }),
+        )
+        ..loadRequest(LoadRequestParams(uri: Uri.parse(blankPageEncoded)));
 
       await pageLoads.stream.first; // Wait for initial page load.
-      final WebViewController controller = await controllerCompleter.future;
-      await controller.runJavascript('location.href = "$secondaryUrl"');
+      await controller.runJavaScript('location.href = "$secondaryUrl"');
 
       await pageLoads.stream.first; // Wait for second page to load.
       final String? currentUrl = await controller.currentUrl();
@@ -1102,52 +801,29 @@
 
   testWidgets('launches with gestureNavigationEnabled on iOS',
       (WidgetTester tester) async {
-    final Completer<WebViewController> controllerCompleter =
-        Completer<WebViewController>();
-    await tester.pumpWidget(
-      Directionality(
-        textDirection: TextDirection.ltr,
-        child: SizedBox(
-          width: 400,
-          height: 300,
-          child: WebView(
-            key: GlobalKey(),
-            initialUrl: primaryUrl,
-            gestureNavigationEnabled: true,
-            onWebViewCreated: (WebViewController controller) {
-              controllerCompleter.complete(controller);
-            },
-          ),
-        ),
-      ),
-    );
-    final WebViewController controller = await controllerCompleter.future;
+    final WebKitWebViewController controller = WebKitWebViewController(
+      WebKitWebViewControllerCreationParams(),
+    )
+      ..setAllowsBackForwardNavigationGestures(true)
+      ..loadRequest(LoadRequestParams(uri: Uri.parse(primaryUrl)));
+
     final String? currentUrl = await controller.currentUrl();
     expect(currentUrl, primaryUrl);
   });
 
   testWidgets('target _blank opens in same window',
       (WidgetTester tester) async {
-    final Completer<WebViewController> controllerCompleter =
-        Completer<WebViewController>();
     final Completer<void> pageLoaded = Completer<void>();
-    await tester.pumpWidget(
-      Directionality(
-        textDirection: TextDirection.ltr,
-        child: WebView(
-          key: GlobalKey(),
-          onWebViewCreated: (WebViewController controller) {
-            controllerCompleter.complete(controller);
-          },
-          javascriptMode: JavascriptMode.unrestricted,
-          onPageFinished: (String url) {
-            pageLoaded.complete(null);
-          },
-        ),
-      ),
-    );
-    final WebViewController controller = await controllerCompleter.future;
-    await controller.runJavascript('window.open("$primaryUrl", "_blank")');
+
+    final PlatformWebViewController controller = PlatformWebViewController(
+      WebKitWebViewControllerCreationParams(),
+    )
+      ..setJavaScriptMode(JavaScriptMode.unrestricted)
+      ..setPlatformNavigationDelegate(WebKitNavigationDelegate(
+        const WebKitNavigationDelegateCreationParams(),
+      )..setOnPageFinished((_) => pageLoaded.complete()));
+
+    await controller.runJavaScript('window.open("$primaryUrl", "_blank")');
     await pageLoaded.future;
     final String? currentUrl = await controller.currentUrl();
     expect(currentUrl, primaryUrl);
@@ -1156,31 +832,22 @@
   testWidgets(
     'can open new window and go back',
     (WidgetTester tester) async {
-      final Completer<WebViewController> controllerCompleter =
-          Completer<WebViewController>();
       Completer<void> pageLoaded = Completer<void>();
-      await tester.pumpWidget(
-        Directionality(
-          textDirection: TextDirection.ltr,
-          child: WebView(
-            key: GlobalKey(),
-            onWebViewCreated: (WebViewController controller) {
-              controllerCompleter.complete(controller);
-            },
-            javascriptMode: JavascriptMode.unrestricted,
-            onPageFinished: (String url) {
-              pageLoaded.complete();
-            },
-            initialUrl: primaryUrl,
-          ),
-        ),
-      );
-      final WebViewController controller = await controllerCompleter.future;
+
+      final PlatformWebViewController controller = PlatformWebViewController(
+        WebKitWebViewControllerCreationParams(),
+      )
+        ..setJavaScriptMode(JavaScriptMode.unrestricted)
+        ..setPlatformNavigationDelegate(WebKitNavigationDelegate(
+          const WebKitNavigationDelegateCreationParams(),
+        )..setOnPageFinished((_) => pageLoaded.complete()))
+        ..loadRequest(LoadRequestParams(uri: Uri.parse(primaryUrl)));
+
       expect(controller.currentUrl(), completion(primaryUrl));
       await pageLoaded.future;
       pageLoaded = Completer<void>();
 
-      await controller.runJavascript('window.open("$secondaryUrl")');
+      await controller.runJavaScript('window.open("$secondaryUrl")');
       await pageLoaded.future;
       pageLoaded = Completer<void>();
       expect(controller.currentUrl(), completion(secondaryUrl));
@@ -1193,26 +860,20 @@
   );
 }
 
-// JavaScript booleans evaluate to different string values on Android and iOS.
-// This utility method returns the string boolean value of the current platform.
-String _webviewBool(bool value) {
-  if (defaultTargetPlatform == TargetPlatform.iOS) {
-    return value ? '1' : '0';
-  }
-  return value ? 'true' : 'false';
-}
-
 /// Returns the value used for the HTTP User-Agent: request header in subsequent HTTP requests.
-Future<String> _getUserAgent(WebViewController controller) async {
-  return controller.runJavascriptReturningResult('navigator.userAgent;');
+Future<String> _getUserAgent(PlatformWebViewController controller) async {
+  return await controller.runJavaScriptReturningResult('navigator.userAgent;')
+      as String;
 }
 
 class ResizableWebView extends StatefulWidget {
-  const ResizableWebView(
-      {Key? key, required this.onResize, required this.onPageFinished})
-      : super(key: key);
+  const ResizableWebView({
+    Key? key,
+    required this.onResize,
+    required this.onPageFinished,
+  }) : super(key: key);
 
-  final JavascriptMessageHandler onResize;
+  final VoidCallback onResize;
   final VoidCallback onPageFinished;
 
   @override
@@ -1220,6 +881,31 @@
 }
 
 class ResizableWebViewState extends State<ResizableWebView> {
+  late final PlatformWebViewController controller = PlatformWebViewController(
+    const PlatformWebViewControllerCreationParams(),
+  )
+    ..setJavaScriptMode(JavaScriptMode.unrestricted)
+    ..setPlatformNavigationDelegate(
+      WebKitNavigationDelegate(
+        const WebKitNavigationDelegateCreationParams(),
+      )..setOnPageFinished((_) => widget.onPageFinished()),
+    )
+    ..addJavaScriptChannel(
+      JavaScriptChannelParams(
+        name: 'Resize',
+        onMessageReceived: (_) {
+          widget.onResize();
+        },
+      ),
+    )
+    ..loadRequest(
+      LoadRequestParams(
+        uri: Uri.parse(
+          'data:text/html;charset=utf-8;base64,${base64Encode(const Utf8Encoder().convert(resizePage))}',
+        ),
+      ),
+    );
+
   double webViewWidth = 200;
   double webViewHeight = 200;
 
@@ -1242,8 +928,6 @@
 
   @override
   Widget build(BuildContext context) {
-    final String resizeTestBase64 =
-        base64Encode(const Utf8Encoder().convert(resizePage));
     return Directionality(
       textDirection: TextDirection.ltr,
       child: Column(
@@ -1251,18 +935,9 @@
           SizedBox(
             width: webViewWidth,
             height: webViewHeight,
-            child: WebView(
-              initialUrl:
-                  'data:text/html;charset=utf-8;base64,$resizeTestBase64',
-              javascriptChannels: <JavascriptChannel>{
-                JavascriptChannel(
-                  name: 'Resize',
-                  onMessageReceived: widget.onResize,
-                ),
-              },
-              onPageFinished: (_) => widget.onPageFinished(),
-              javascriptMode: JavascriptMode.unrestricted,
-            ),
+            child: PlatformWebViewWidget(
+              PlatformWebViewWidgetCreationParams(controller: controller),
+            ).build(context),
           ),
           TextButton(
             key: const Key('resizeButton'),
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/example/lib/navigation_decision.dart b/packages/webview_flutter/webview_flutter_wkwebview/example/lib/legacy/navigation_decision.dart
similarity index 100%
rename from packages/webview_flutter/webview_flutter_wkwebview/example/lib/navigation_decision.dart
rename to packages/webview_flutter/webview_flutter_wkwebview/example/lib/legacy/navigation_decision.dart
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/example/lib/navigation_request.dart b/packages/webview_flutter/webview_flutter_wkwebview/example/lib/legacy/navigation_request.dart
similarity index 100%
rename from packages/webview_flutter/webview_flutter_wkwebview/example/lib/navigation_request.dart
rename to packages/webview_flutter/webview_flutter_wkwebview/example/lib/legacy/navigation_request.dart
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/example/lib/web_view.dart b/packages/webview_flutter/webview_flutter_wkwebview/example/lib/legacy/web_view.dart
similarity index 98%
rename from packages/webview_flutter/webview_flutter_wkwebview/example/lib/web_view.dart
rename to packages/webview_flutter/webview_flutter_wkwebview/example/lib/legacy/web_view.dart
index 11edefb..d99b309 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/example/lib/web_view.dart
+++ b/packages/webview_flutter/webview_flutter_wkwebview/example/lib/legacy/web_view.dart
@@ -8,8 +8,10 @@
 import 'package:flutter/foundation.dart';
 import 'package:flutter/gestures.dart';
 import 'package:flutter/widgets.dart';
-import 'package:webview_flutter_platform_interface/webview_flutter_platform_interface.dart';
-import 'package:webview_flutter_wkwebview/webview_flutter_wkwebview.dart';
+// ignore: implementation_imports
+import 'package:webview_flutter_platform_interface/src/webview_flutter_platform_interface_legacy.dart';
+// ignore: implementation_imports
+import 'package:webview_flutter_wkwebview/src/webview_flutter_wkwebview_legacy.dart';
 
 import 'navigation_decision.dart';
 import 'navigation_request.dart';
@@ -639,8 +641,10 @@
     required bool isForMainFrame,
   }) async {
     if (url.startsWith('https://www.youtube.com/')) {
+      debugPrint('blocking navigation to $url');
       return false;
     }
+    debugPrint('allowing navigation to $url');
     return true;
   }
 
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/example/lib/main.dart b/packages/webview_flutter/webview_flutter_wkwebview/example/lib/main.dart
index c1a456e..84aced1 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/example/lib/main.dart
+++ b/packages/webview_flutter/webview_flutter_wkwebview/example/lib/main.dart
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// ignore_for_file: public_member_api_docs, avoid_print
+// ignore_for_file: public_member_api_docs
 
 import 'dart:async';
 import 'dart:convert';
@@ -12,13 +12,10 @@
 import 'package:flutter/material.dart';
 import 'package:path_provider/path_provider.dart';
 import 'package:webview_flutter_platform_interface/webview_flutter_platform_interface.dart';
-
-import 'navigation_decision.dart';
-import 'navigation_request.dart';
-import 'web_view.dart';
+import 'package:webview_flutter_wkwebview/webview_flutter_wkwebview.dart';
 
 void main() {
-  runApp(const MaterialApp(home: _WebViewExample()));
+  runApp(const MaterialApp(home: WebViewExample()));
 }
 
 const String kNavigationExamplePage = '''
@@ -36,6 +33,26 @@
 </html>
 ''';
 
+const String kLocalExamplePage = '''
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<title>Load file or HTML string example</title>
+</head>
+<body>
+
+<h1>Local demo page</h1>
+<p>
+  This is an example page used to demonstrate how to load a local file or HTML
+  string using the <a href="https://pub.dev/packages/webview_flutter">Flutter
+  webview</a> plugin.
+</p>
+
+</body>
+</html>
+''';
+
+// NOTE: This is used by the transparency test in `example/ios/RunnerUITests/FLTWebViewUITests.m`.
 const String kTransparentBackgroundPage = '''
 <!DOCTYPE html>
 <html>
@@ -57,39 +74,69 @@
 </html>
 ''';
 
-const String kLocalFileExamplePage = '''
-<!DOCTYPE html>
-<html lang="en">
-<head>
-<title>Load file or HTML string example</title>
-</head>
-<body>
+class WebViewExample extends StatefulWidget {
+  const WebViewExample({Key? key, this.cookieManager}) : super(key: key);
 
-<h1>Local demo page</h1>
-<p>
-  This is an example page used to demonstrate how to load a local file or HTML
-  string using the <a href="https://pub.dev/packages/webview_flutter">Flutter
-  webview</a> plugin.
-</p>
-
-</body>
-</html>
-''';
-
-class _WebViewExample extends StatefulWidget {
-  const _WebViewExample({Key? key}) : super(key: key);
+  final PlatformWebViewCookieManager? cookieManager;
 
   @override
-  _WebViewExampleState createState() => _WebViewExampleState();
+  State<WebViewExample> createState() => _WebViewExampleState();
 }
 
-class _WebViewExampleState extends State<_WebViewExample> {
-  final Completer<WebViewController> _controller =
-      Completer<WebViewController>();
+class _WebViewExampleState extends State<WebViewExample> {
+  late final PlatformWebViewController _controller;
 
   @override
   void initState() {
     super.initState();
+
+    _controller = PlatformWebViewController(
+      WebKitWebViewControllerCreationParams(allowsInlineMediaPlayback: true),
+    )
+      ..setJavaScriptMode(JavaScriptMode.unrestricted)
+      ..setBackgroundColor(const Color(0x80000000))
+      ..setPlatformNavigationDelegate(
+        PlatformNavigationDelegate(
+          const PlatformNavigationDelegateCreationParams(),
+        )
+          ..setOnProgress((int progress) {
+            debugPrint('WebView is loading (progress : $progress%)');
+          })
+          ..setOnPageStarted((String url) {
+            debugPrint('Page started loading: $url');
+          })
+          ..setOnPageFinished((String url) {
+            debugPrint('Page finished loading: $url');
+          })
+          ..setOnWebResourceError((WebResourceError error) {
+            debugPrint('''
+Page resource error:
+  code: ${error.errorCode}
+  description: ${error.description}
+  errorType: ${error.errorType}
+  isForMainFrame: ${error.isForMainFrame}
+          ''');
+          })
+          ..setOnNavigationRequest((NavigationRequest request) {
+            if (request.url.startsWith('https://www.youtube.com/')) {
+              debugPrint('blocking navigation to ${request.url}');
+              return NavigationDecision.prevent;
+            }
+            debugPrint('allowing navigation to ${request.url}');
+            return NavigationDecision.navigate;
+          }),
+      )
+      ..addJavaScriptChannel(JavaScriptChannelParams(
+        name: 'Toaster',
+        onMessageReceived: (JavaScriptMessage message) {
+          ScaffoldMessenger.of(context).showSnackBar(
+            SnackBar(content: Text(message.message)),
+          );
+        },
+      ))
+      ..loadRequest(LoadRequestParams(
+        uri: Uri.parse('https://flutter.dev'),
+      ));
   }
 
   @override
@@ -100,64 +147,34 @@
         title: const Text('Flutter WebView example'),
         // This drop down menu demonstrates that Flutter widgets can be shown over the web view.
         actions: <Widget>[
-          _NavigationControls(_controller.future),
-          _SampleMenu(_controller.future),
+          NavigationControls(webViewController: _controller),
+          SampleMenu(
+            webViewController: _controller,
+            cookieManager: widget.cookieManager,
+          ),
         ],
       ),
-      body: WebView(
-        initialUrl: 'https://flutter.dev/',
-        onWebViewCreated: (WebViewController controller) {
-          _controller.complete(controller);
-        },
-        javascriptChannels: _createJavascriptChannels(context),
-        javascriptMode: JavascriptMode.unrestricted,
-        navigationDelegate: (NavigationRequest request) {
-          if (request.url.startsWith('https://www.youtube.com/')) {
-            print('blocking navigation to $request}');
-            return NavigationDecision.prevent;
-          }
-          print('allowing navigation to $request');
-          return NavigationDecision.navigate;
-        },
-        backgroundColor: const Color(0x80000000),
-      ),
+      body: PlatformWebViewWidget(
+        PlatformWebViewWidgetCreationParams(controller: _controller),
+      ).build(context),
       floatingActionButton: favoriteButton(),
     );
   }
 
   Widget favoriteButton() {
-    return FutureBuilder<WebViewController>(
-        future: _controller.future,
-        builder: (BuildContext context,
-            AsyncSnapshot<WebViewController> controller) {
-          if (controller.hasData) {
-            return FloatingActionButton(
-              onPressed: () async {
-                final String url = (await controller.data!.currentUrl())!;
-                ScaffoldMessenger.of(context).showSnackBar(
-                  SnackBar(content: Text('Favorited $url')),
-                );
-              },
-              child: const Icon(Icons.favorite),
-            );
-          }
-          return Container();
-        });
+    return FloatingActionButton(
+      onPressed: () async {
+        final String? url = await _controller.currentUrl();
+        ScaffoldMessenger.of(context).showSnackBar(
+          SnackBar(content: Text('Favorited $url')),
+        );
+      },
+      child: const Icon(Icons.favorite),
+    );
   }
 }
 
-Set<JavascriptChannel> _createJavascriptChannels(BuildContext context) {
-  return <JavascriptChannel>{
-    JavascriptChannel(
-        name: 'Snackbar',
-        onMessageReceived: (JavascriptMessage message) {
-          ScaffoldMessenger.of(context)
-              .showSnackBar(SnackBar(content: Text(message.message)));
-        }),
-  };
-}
-
-enum _MenuOptions {
+enum MenuOptions {
   showUserAgent,
   listCookies,
   clearCookies,
@@ -165,143 +182,144 @@
   listCache,
   clearCache,
   navigationDelegate,
-  loadFlutterAsset,
-  loadLocalFile,
-  loadHtmlString,
   doPostRequest,
-  setCookie,
+  loadLocalFile,
+  loadFlutterAsset,
+  loadHtmlString,
   transparentBackground,
+  setCookie,
 }
 
-class _SampleMenu extends StatelessWidget {
-  const _SampleMenu(this.controller);
+class SampleMenu extends StatelessWidget {
+  SampleMenu({
+    Key? key,
+    required this.webViewController,
+    PlatformWebViewCookieManager? cookieManager,
+  })  : cookieManager = cookieManager ??
+            PlatformWebViewCookieManager(
+              const PlatformWebViewCookieManagerCreationParams(),
+            ),
+        super(key: key);
 
-  final Future<WebViewController> controller;
+  final PlatformWebViewController webViewController;
+  late final PlatformWebViewCookieManager cookieManager;
 
   @override
   Widget build(BuildContext context) {
-    return FutureBuilder<WebViewController>(
-      future: controller,
-      builder:
-          (BuildContext context, AsyncSnapshot<WebViewController> controller) {
-        return PopupMenuButton<_MenuOptions>(
-          key: const ValueKey<String>('ShowPopupMenu'),
-          onSelected: (_MenuOptions value) {
-            switch (value) {
-              case _MenuOptions.showUserAgent:
-                _onShowUserAgent(controller.data!, context);
-                break;
-              case _MenuOptions.listCookies:
-                _onListCookies(controller.data!, context);
-                break;
-              case _MenuOptions.clearCookies:
-                _onClearCookies(controller.data!, context);
-                break;
-              case _MenuOptions.addToCache:
-                _onAddToCache(controller.data!, context);
-                break;
-              case _MenuOptions.listCache:
-                _onListCache(controller.data!, context);
-                break;
-              case _MenuOptions.clearCache:
-                _onClearCache(controller.data!, context);
-                break;
-              case _MenuOptions.navigationDelegate:
-                _onNavigationDelegateExample(controller.data!, context);
-                break;
-              case _MenuOptions.loadFlutterAsset:
-                _onLoadFlutterAssetExample(controller.data!, context);
-                break;
-              case _MenuOptions.loadLocalFile:
-                _onLoadLocalFileExample(controller.data!, context);
-                break;
-              case _MenuOptions.loadHtmlString:
-                _onLoadHtmlStringExample(controller.data!, context);
-                break;
-              case _MenuOptions.doPostRequest:
-                _onDoPostRequest(controller.data!, context);
-                break;
-              case _MenuOptions.setCookie:
-                _onSetCookie(controller.data!, context);
-                break;
-              case _MenuOptions.transparentBackground:
-                _onTransparentBackground(controller.data!, context);
-                break;
-            }
-          },
-          itemBuilder: (BuildContext context) => <PopupMenuItem<_MenuOptions>>[
-            PopupMenuItem<_MenuOptions>(
-              value: _MenuOptions.showUserAgent,
-              enabled: controller.hasData,
-              child: const Text('Show user agent'),
-            ),
-            const PopupMenuItem<_MenuOptions>(
-              value: _MenuOptions.listCookies,
-              child: Text('List cookies'),
-            ),
-            const PopupMenuItem<_MenuOptions>(
-              value: _MenuOptions.clearCookies,
-              child: Text('Clear cookies'),
-            ),
-            const PopupMenuItem<_MenuOptions>(
-              value: _MenuOptions.addToCache,
-              child: Text('Add to cache'),
-            ),
-            const PopupMenuItem<_MenuOptions>(
-              value: _MenuOptions.listCache,
-              child: Text('List cache'),
-            ),
-            const PopupMenuItem<_MenuOptions>(
-              value: _MenuOptions.clearCache,
-              child: Text('Clear cache'),
-            ),
-            const PopupMenuItem<_MenuOptions>(
-              value: _MenuOptions.navigationDelegate,
-              child: Text('Navigation Delegate example'),
-            ),
-            const PopupMenuItem<_MenuOptions>(
-              value: _MenuOptions.loadFlutterAsset,
-              child: Text('Load Flutter Asset'),
-            ),
-            const PopupMenuItem<_MenuOptions>(
-              value: _MenuOptions.loadHtmlString,
-              child: Text('Load HTML string'),
-            ),
-            const PopupMenuItem<_MenuOptions>(
-              value: _MenuOptions.loadLocalFile,
-              child: Text('Load local file'),
-            ),
-            const PopupMenuItem<_MenuOptions>(
-              value: _MenuOptions.doPostRequest,
-              child: Text('Post Request'),
-            ),
-            const PopupMenuItem<_MenuOptions>(
-              value: _MenuOptions.setCookie,
-              child: Text('Set Cookie'),
-            ),
-            const PopupMenuItem<_MenuOptions>(
-              key: ValueKey<String>('ShowTransparentBackgroundExample'),
-              value: _MenuOptions.transparentBackground,
-              child: Text('Transparent background example'),
-            ),
-          ],
-        );
+    return PopupMenuButton<MenuOptions>(
+      key: const ValueKey<String>('ShowPopupMenu'),
+      onSelected: (MenuOptions value) {
+        switch (value) {
+          case MenuOptions.showUserAgent:
+            _onShowUserAgent();
+            break;
+          case MenuOptions.listCookies:
+            _onListCookies(context);
+            break;
+          case MenuOptions.clearCookies:
+            _onClearCookies(context);
+            break;
+          case MenuOptions.addToCache:
+            _onAddToCache(context);
+            break;
+          case MenuOptions.listCache:
+            _onListCache();
+            break;
+          case MenuOptions.clearCache:
+            _onClearCache(context);
+            break;
+          case MenuOptions.navigationDelegate:
+            _onNavigationDelegateExample();
+            break;
+          case MenuOptions.doPostRequest:
+            _onDoPostRequest();
+            break;
+          case MenuOptions.loadLocalFile:
+            _onLoadLocalFileExample();
+            break;
+          case MenuOptions.loadFlutterAsset:
+            _onLoadFlutterAssetExample();
+            break;
+          case MenuOptions.loadHtmlString:
+            _onLoadHtmlStringExample();
+            break;
+          case MenuOptions.transparentBackground:
+            _onTransparentBackground();
+            break;
+          case MenuOptions.setCookie:
+            _onSetCookie();
+            break;
+        }
       },
+      itemBuilder: (BuildContext context) => <PopupMenuItem<MenuOptions>>[
+        const PopupMenuItem<MenuOptions>(
+          value: MenuOptions.showUserAgent,
+          child: Text('Show user agent'),
+        ),
+        const PopupMenuItem<MenuOptions>(
+          value: MenuOptions.listCookies,
+          child: Text('List cookies'),
+        ),
+        const PopupMenuItem<MenuOptions>(
+          value: MenuOptions.clearCookies,
+          child: Text('Clear cookies'),
+        ),
+        const PopupMenuItem<MenuOptions>(
+          value: MenuOptions.addToCache,
+          child: Text('Add to cache'),
+        ),
+        const PopupMenuItem<MenuOptions>(
+          value: MenuOptions.listCache,
+          child: Text('List cache'),
+        ),
+        const PopupMenuItem<MenuOptions>(
+          value: MenuOptions.clearCache,
+          child: Text('Clear cache'),
+        ),
+        const PopupMenuItem<MenuOptions>(
+          value: MenuOptions.navigationDelegate,
+          child: Text('Navigation Delegate example'),
+        ),
+        const PopupMenuItem<MenuOptions>(
+          value: MenuOptions.doPostRequest,
+          child: Text('Post Request'),
+        ),
+        const PopupMenuItem<MenuOptions>(
+          value: MenuOptions.loadHtmlString,
+          child: Text('Load HTML string'),
+        ),
+        const PopupMenuItem<MenuOptions>(
+          value: MenuOptions.loadLocalFile,
+          child: Text('Load local file'),
+        ),
+        const PopupMenuItem<MenuOptions>(
+          value: MenuOptions.loadFlutterAsset,
+          child: Text('Load Flutter Asset'),
+        ),
+        const PopupMenuItem<MenuOptions>(
+          value: MenuOptions.setCookie,
+          child: Text('Set cookie'),
+        ),
+        const PopupMenuItem<MenuOptions>(
+          key: ValueKey<String>('ShowTransparentBackgroundExample'),
+          value: MenuOptions.transparentBackground,
+          child: Text('Transparent background example'),
+        ),
+      ],
     );
   }
 
-  Future<void> _onShowUserAgent(
-      WebViewController controller, BuildContext context) async {
-    // Send a message with the user agent string to the Snackbar JavaScript channel we registered
+  Future<void> _onShowUserAgent() {
+    // Send a message with the user agent string to the Toaster JavaScript channel we registered
     // with the WebView.
-    await controller.runJavascript(
-        'Snackbar.postMessage("User Agent: " + navigator.userAgent);');
+    return webViewController.runJavaScript(
+      'Toaster.postMessage("User Agent: " + navigator.userAgent);',
+    );
   }
 
-  Future<void> _onListCookies(
-      WebViewController controller, BuildContext context) async {
-    final String cookies =
-        await controller.runJavascriptReturningResult('document.cookie');
+  Future<void> _onListCookies(BuildContext context) async {
+    final String cookies = await webViewController
+        .runJavaScriptReturningResult('document.cookie') as String;
     ScaffoldMessenger.of(context).showSnackBar(SnackBar(
       content: Column(
         mainAxisAlignment: MainAxisAlignment.end,
@@ -314,34 +332,32 @@
     ));
   }
 
-  Future<void> _onAddToCache(
-      WebViewController controller, BuildContext context) async {
-    await controller.runJavascript(
-        'caches.open("test_caches_entry"); localStorage["test_localStorage"] = "dummy_entry";');
+  Future<void> _onAddToCache(BuildContext context) async {
+    await webViewController.runJavaScript(
+      'caches.open("test_caches_entry"); localStorage["test_localStorage"] = "dummy_entry";',
+    );
     ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
       content: Text('Added a test entry to cache.'),
     ));
   }
 
-  Future<void> _onListCache(
-      WebViewController controller, BuildContext context) async {
-    await controller.runJavascript('caches.keys()'
+  Future<void> _onListCache() {
+    return webViewController.runJavaScript('caches.keys()'
         // ignore: missing_whitespace_between_adjacent_strings
         '.then((cacheKeys) => JSON.stringify({"cacheKeys" : cacheKeys, "localStorage" : localStorage}))'
-        '.then((caches) => Snackbar.postMessage(caches))');
+        '.then((caches) => Toaster.postMessage(caches))');
   }
 
-  Future<void> _onClearCache(
-      WebViewController controller, BuildContext context) async {
-    await controller.clearCache();
+  Future<void> _onClearCache(BuildContext context) async {
+    await webViewController.clearCache();
+    await webViewController.clearLocalStorage();
     ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
       content: Text('Cache cleared.'),
     ));
   }
 
-  Future<void> _onClearCookies(
-      WebViewController controller, BuildContext context) async {
-    final bool hadCookies = await WebView.platform.clearCookies();
+  Future<void> _onClearCookies(BuildContext context) async {
+    final bool hadCookies = await cookieManager.clearCookies();
     String message = 'There were cookies. Now, they are gone!';
     if (!hadCookies) {
       message = 'There are no cookies.';
@@ -351,48 +367,58 @@
     ));
   }
 
-  Future<void> _onNavigationDelegateExample(
-      WebViewController controller, BuildContext context) async {
-    final String contentBase64 =
-        base64Encode(const Utf8Encoder().convert(kNavigationExamplePage));
-    await controller.loadUrl('data:text/html;base64,$contentBase64');
-  }
-
-  Future<void> _onLoadFlutterAssetExample(
-      WebViewController controller, BuildContext context) async {
-    await controller.loadFlutterAsset('assets/www/index.html');
-  }
-
-  Future<void> _onLoadLocalFileExample(
-      WebViewController controller, BuildContext context) async {
-    final String pathToIndex = await _prepareLocalFile();
-
-    await controller.loadFile(pathToIndex);
-  }
-
-  Future<void> _onLoadHtmlStringExample(
-      WebViewController controller, BuildContext context) async {
-    await controller.loadHtmlString(kLocalFileExamplePage);
-  }
-
-  Future<void> _onDoPostRequest(
-      WebViewController controller, BuildContext context) async {
-    final WebViewRequest request = WebViewRequest(
-      uri: Uri.parse('https://httpbin.org/post'),
-      method: WebViewRequestMethod.post,
-      headers: <String, String>{'foo': 'bar', 'Content-Type': 'text/plain'},
-      body: Uint8List.fromList('Test Body'.codeUnits),
+  Future<void> _onNavigationDelegateExample() {
+    final String contentBase64 = base64Encode(
+      const Utf8Encoder().convert(kNavigationExamplePage),
     );
-    await controller.loadRequest(request);
+    return webViewController.loadRequest(
+      LoadRequestParams(
+        uri: Uri.parse('data:text/html;base64,$contentBase64'),
+      ),
+    );
   }
 
-  Future<void> _onSetCookie(
-      WebViewController controller, BuildContext context) async {
-    await WebViewCookieManager.instance.setCookie(
+  Future<void> _onSetCookie() async {
+    await cookieManager.setCookie(
       const WebViewCookie(
-          name: 'foo', value: 'bar', domain: 'httpbin.org', path: '/anything'),
+        name: 'foo',
+        value: 'bar',
+        domain: 'httpbin.org',
+        path: '/anything',
+      ),
     );
-    await controller.loadUrl('https://httpbin.org/anything');
+    await webViewController.loadRequest(LoadRequestParams(
+      uri: Uri.parse('https://httpbin.org/anything'),
+    ));
+  }
+
+  Future<void> _onDoPostRequest() {
+    return webViewController.loadRequest(LoadRequestParams(
+      uri: Uri.parse('https://httpbin.org/post'),
+      method: LoadRequestMethod.post,
+      headers: const <String, String>{
+        'foo': 'bar',
+        'Content-Type': 'text/plain',
+      },
+      body: Uint8List.fromList('Test Body'.codeUnits),
+    ));
+  }
+
+  Future<void> _onLoadLocalFileExample() async {
+    final String pathToIndex = await _prepareLocalFile();
+    await webViewController.loadFile(pathToIndex);
+  }
+
+  Future<void> _onLoadFlutterAssetExample() {
+    return webViewController.loadFlutterAsset('assets/www/index.html');
+  }
+
+  Future<void> _onLoadHtmlStringExample() {
+    return webViewController.loadHtmlString(kLocalExamplePage);
+  }
+
+  Future<void> _onTransparentBackground() {
+    return webViewController.loadHtmlString(kTransparentBackgroundPage);
   }
 
   Widget _getCookieList(String cookies) {
@@ -409,85 +435,59 @@
     );
   }
 
-  Future<void> _onTransparentBackground(
-      WebViewController controller, BuildContext context) async {
-    await controller.loadHtmlString(kTransparentBackgroundPage);
-  }
-
   static Future<String> _prepareLocalFile() async {
     final String tmpDir = (await getTemporaryDirectory()).path;
-    final File indexFile = File('$tmpDir/www/index.html');
+    final File indexFile = File(
+        <String>{tmpDir, 'www', 'index.html'}.join(Platform.pathSeparator));
 
-    await Directory('$tmpDir/www').create(recursive: true);
-    await indexFile.writeAsString(kLocalFileExamplePage);
+    await indexFile.create(recursive: true);
+    await indexFile.writeAsString(kLocalExamplePage);
 
     return indexFile.path;
   }
 }
 
-class _NavigationControls extends StatelessWidget {
-  const _NavigationControls(this._webViewControllerFuture)
-      : assert(_webViewControllerFuture != null);
+class NavigationControls extends StatelessWidget {
+  const NavigationControls({Key? key, required this.webViewController})
+      : super(key: key);
 
-  final Future<WebViewController> _webViewControllerFuture;
+  final PlatformWebViewController webViewController;
 
   @override
   Widget build(BuildContext context) {
-    return FutureBuilder<WebViewController>(
-      future: _webViewControllerFuture,
-      builder:
-          (BuildContext context, AsyncSnapshot<WebViewController> snapshot) {
-        final bool webViewReady =
-            snapshot.connectionState == ConnectionState.done;
-        final WebViewController? controller = snapshot.data;
-
-        return Row(
-          children: <Widget>[
-            IconButton(
-              icon: const Icon(Icons.arrow_back_ios),
-              onPressed: !webViewReady
-                  ? null
-                  : () async {
-                      if (await controller!.canGoBack()) {
-                        await controller.goBack();
-                      } else {
-                        ScaffoldMessenger.of(context).showSnackBar(
-                          const SnackBar(content: Text('No back history item')),
-                        );
-                        return;
-                      }
-                    },
-            ),
-            IconButton(
-              icon: const Icon(Icons.arrow_forward_ios),
-              onPressed: !webViewReady
-                  ? null
-                  : () async {
-                      if (await controller!.canGoForward()) {
-                        await controller.goForward();
-                      } else {
-                        ScaffoldMessenger.of(context).showSnackBar(
-                          const SnackBar(
-                              content: Text('No forward history item')),
-                        );
-                        return;
-                      }
-                    },
-            ),
-            IconButton(
-              icon: const Icon(Icons.replay),
-              onPressed: !webViewReady
-                  ? null
-                  : () {
-                      controller!.reload();
-                    },
-            ),
-          ],
-        );
-      },
+    return Row(
+      children: <Widget>[
+        IconButton(
+          icon: const Icon(Icons.arrow_back_ios),
+          onPressed: () async {
+            if (await webViewController.canGoBack()) {
+              await webViewController.goBack();
+            } else {
+              ScaffoldMessenger.of(context).showSnackBar(
+                const SnackBar(content: Text('No back history item')),
+              );
+              return;
+            }
+          },
+        ),
+        IconButton(
+          icon: const Icon(Icons.arrow_forward_ios),
+          onPressed: () async {
+            if (await webViewController.canGoForward()) {
+              await webViewController.goForward();
+            } else {
+              ScaffoldMessenger.of(context).showSnackBar(
+                const SnackBar(content: Text('No forward history item')),
+              );
+              return;
+            }
+          },
+        ),
+        IconButton(
+          icon: const Icon(Icons.replay),
+          onPressed: () => webViewController.reload(),
+        ),
+      ],
     );
   }
 }
-
-/// Callback type for handling messages sent from JavaScript running in a web view.
-typedef JavascriptMessageHandler = void Function(JavascriptMessage message);
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/example/pubspec.yaml b/packages/webview_flutter/webview_flutter_wkwebview/example/pubspec.yaml
index a3f65b8..7ccb302 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/example/pubspec.yaml
+++ b/packages/webview_flutter/webview_flutter_wkwebview/example/pubspec.yaml
@@ -9,7 +9,7 @@
   flutter:
     sdk: flutter
   path_provider: ^2.0.6
-  webview_flutter_platform_interface: ^1.8.0
+  webview_flutter_platform_interface: ^2.0.0
   webview_flutter_wkwebview:
     # When depending on this package from a real application you should use:
     #   webview_flutter: ^x.y.z
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/lib/src/web_kit_webview_widget.dart b/packages/webview_flutter/webview_flutter_wkwebview/lib/src/legacy/web_kit_webview_widget.dart
similarity index 98%
rename from packages/webview_flutter/webview_flutter_wkwebview/lib/src/web_kit_webview_widget.dart
rename to packages/webview_flutter/webview_flutter_wkwebview/lib/src/legacy/web_kit_webview_widget.dart
index 3272109..cc901a4 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/lib/src/web_kit_webview_widget.dart
+++ b/packages/webview_flutter/webview_flutter_wkwebview/lib/src/legacy/web_kit_webview_widget.dart
@@ -9,11 +9,12 @@
 import 'package:flutter/material.dart';
 import 'package:flutter/services.dart';
 import 'package:path/path.dart' as path;
-import 'package:webview_flutter_platform_interface/webview_flutter_platform_interface.dart';
+// ignore: implementation_imports
+import 'package:webview_flutter_platform_interface/src/webview_flutter_platform_interface_legacy.dart';
 
-import 'common/weak_reference_utils.dart';
-import 'foundation/foundation.dart';
-import 'web_kit/web_kit.dart';
+import '../common/weak_reference_utils.dart';
+import '../foundation/foundation.dart';
+import '../web_kit/web_kit.dart';
 
 /// A [Widget] that displays a [WKWebView].
 class WebKitWebViewWidget extends StatefulWidget {
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/lib/src/webview_cupertino.dart b/packages/webview_flutter/webview_flutter_wkwebview/lib/src/legacy/webview_cupertino.dart
similarity index 92%
rename from packages/webview_flutter/webview_flutter_wkwebview/lib/src/webview_cupertino.dart
rename to packages/webview_flutter/webview_flutter_wkwebview/lib/src/legacy/webview_cupertino.dart
index 616f00c..5ad959c 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/lib/src/webview_cupertino.dart
+++ b/packages/webview_flutter/webview_flutter_wkwebview/lib/src/legacy/webview_cupertino.dart
@@ -8,9 +8,10 @@
 import 'package:flutter/gestures.dart';
 import 'package:flutter/services.dart';
 import 'package:flutter/widgets.dart';
-import 'package:webview_flutter_platform_interface/webview_flutter_platform_interface.dart';
+// ignore: implementation_imports
+import 'package:webview_flutter_platform_interface/src/webview_flutter_platform_interface_legacy.dart';
 
-import 'foundation/foundation.dart';
+import '../foundation/foundation.dart';
 import 'web_kit_webview_widget.dart';
 
 /// Builds an iOS webview.
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/lib/src/wkwebview_cookie_manager.dart b/packages/webview_flutter/webview_flutter_wkwebview/lib/src/legacy/wkwebview_cookie_manager.dart
similarity index 88%
rename from packages/webview_flutter/webview_flutter_wkwebview/lib/src/wkwebview_cookie_manager.dart
rename to packages/webview_flutter/webview_flutter_wkwebview/lib/src/legacy/wkwebview_cookie_manager.dart
index cdbf262..59dce55 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/lib/src/wkwebview_cookie_manager.dart
+++ b/packages/webview_flutter/webview_flutter_wkwebview/lib/src/legacy/wkwebview_cookie_manager.dart
@@ -2,10 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import 'package:webview_flutter_platform_interface/webview_flutter_platform_interface.dart';
+// ignore: implementation_imports
+import 'package:webview_flutter_platform_interface/src/webview_flutter_platform_interface_legacy.dart';
 
-import 'foundation/foundation.dart';
-import 'web_kit/web_kit.dart';
+import '../foundation/foundation.dart';
+import '../web_kit/web_kit.dart';
 
 /// Handles all cookie operations for the WebView platform.
 class WKWebViewCookieManager extends WebViewCookieManagerPlatform {
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/lib/src/v4/webview_flutter_wkwebview.dart b/packages/webview_flutter/webview_flutter_wkwebview/lib/src/v4/webview_flutter_wkwebview.dart
deleted file mode 100644
index f54fb73..0000000
--- a/packages/webview_flutter/webview_flutter_wkwebview/lib/src/v4/webview_flutter_wkwebview.dart
+++ /dev/null
@@ -1,9 +0,0 @@
-// Copyright 2013 The Flutter Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-library webview_flutter_wkwebview;
-
-export 'src/webkit_webview_controller.dart';
-export 'src/webkit_webview_cookie_manager.dart';
-export 'src/webkit_webview_platform.dart';
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/lib/src/v4/src/webkit_proxy.dart b/packages/webview_flutter/webview_flutter_wkwebview/lib/src/webkit_proxy.dart
similarity index 87%
rename from packages/webview_flutter/webview_flutter_wkwebview/lib/src/v4/src/webkit_proxy.dart
rename to packages/webview_flutter/webview_flutter_wkwebview/lib/src/webkit_proxy.dart
index e3d1f60..2cdc7e2 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/lib/src/v4/src/webkit_proxy.dart
+++ b/packages/webview_flutter/webview_flutter_wkwebview/lib/src/webkit_proxy.dart
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import '../../foundation/foundation.dart';
-import '../../web_kit/web_kit.dart';
+import 'foundation/foundation.dart';
+import 'web_kit/web_kit.dart';
 
 // This convenience method was added because Dart doesn't support constant
 // function literals: https://github.com/dart-lang/language/issues/1048.
@@ -27,6 +27,7 @@
     this.createScriptMessageHandler = WKScriptMessageHandler.new,
     this.defaultWebsiteDataStore = _defaultWebsiteDataStore,
     this.createNavigationDelegate = WKNavigationDelegate.new,
+    this.createUIDelegate = WKUIDelegate.new,
   });
 
   /// Constructs a [WKWebView].
@@ -70,4 +71,14 @@
         didFailProvisionalNavigation,
     void Function(WKWebView webView)? webViewWebContentProcessDidTerminate,
   }) createNavigationDelegate;
+
+  /// Contructs a [WKUIDelegate].
+  final WKUIDelegate Function({
+    void Function(
+      WKWebView webView,
+      WKWebViewConfiguration configuration,
+      WKNavigationAction navigationAction,
+    )?
+        onCreateWebView,
+  }) createUIDelegate;
 }
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/lib/src/v4/src/webkit_webview_controller.dart b/packages/webview_flutter/webview_flutter_wkwebview/lib/src/webkit_webview_controller.dart
similarity index 79%
rename from packages/webview_flutter/webview_flutter_wkwebview/lib/src/v4/src/webkit_webview_controller.dart
rename to packages/webview_flutter/webview_flutter_wkwebview/lib/src/webkit_webview_controller.dart
index 117aa78..4821941 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/lib/src/v4/src/webkit_webview_controller.dart
+++ b/packages/webview_flutter/webview_flutter_wkwebview/lib/src/webkit_webview_controller.dart
@@ -9,14 +9,34 @@
 import 'package:flutter/material.dart';
 import 'package:flutter/services.dart';
 import 'package:path/path.dart' as path;
-import 'package:webview_flutter_platform_interface/v4/webview_flutter_platform_interface.dart';
+import 'package:webview_flutter_platform_interface/webview_flutter_platform_interface.dart';
 
-import '../../common/instance_manager.dart';
-import '../../common/weak_reference_utils.dart';
-import '../../foundation/foundation.dart';
-import '../../web_kit/web_kit.dart';
+import 'common/instance_manager.dart';
+import 'common/weak_reference_utils.dart';
+import 'foundation/foundation.dart';
+import 'web_kit/web_kit.dart';
 import 'webkit_proxy.dart';
 
+/// Media types that can require a user gesture to begin playing.
+///
+/// See [WebKitWebViewControllerCreationParams.mediaTypesRequiringUserAction].
+enum PlaybackMediaTypes {
+  /// A media type that contains audio.
+  audio,
+
+  /// A media type that contains video.
+  video;
+
+  WKAudiovisualMediaType _toWKAudiovisualMediaType() {
+    switch (this) {
+      case PlaybackMediaTypes.audio:
+        return WKAudiovisualMediaType.audio;
+      case PlaybackMediaTypes.video:
+        return WKAudiovisualMediaType.video;
+    }
+  }
+}
+
 /// Object specifying creation parameters for a [WebKitWebViewController].
 @immutable
 class WebKitWebViewControllerCreationParams
@@ -24,7 +44,27 @@
   /// Constructs a [WebKitWebViewControllerCreationParams].
   WebKitWebViewControllerCreationParams({
     @visibleForTesting this.webKitProxy = const WebKitProxy(),
-  }) : _configuration = webKitProxy.createWebViewConfiguration();
+    this.mediaTypesRequiringUserAction = const <PlaybackMediaTypes>{
+      PlaybackMediaTypes.audio,
+      PlaybackMediaTypes.video,
+    },
+    this.allowsInlineMediaPlayback = false,
+  }) : _configuration = webKitProxy.createWebViewConfiguration() {
+    if (mediaTypesRequiringUserAction.isEmpty) {
+      _configuration.setMediaTypesRequiringUserActionForPlayback(
+        <WKAudiovisualMediaType>{WKAudiovisualMediaType.none},
+      );
+    } else {
+      _configuration.setMediaTypesRequiringUserActionForPlayback(
+        mediaTypesRequiringUserAction
+            .map<WKAudiovisualMediaType>(
+              (PlaybackMediaTypes type) => type._toWKAudiovisualMediaType(),
+            )
+            .toSet(),
+      );
+    }
+    _configuration.setAllowsInlineMediaPlayback(allowsInlineMediaPlayback);
+  }
 
   /// Constructs a [WebKitWebViewControllerCreationParams] using a
   /// [PlatformWebViewControllerCreationParams].
@@ -33,10 +73,31 @@
     // ignore: avoid_unused_constructor_parameters
     PlatformWebViewControllerCreationParams params, {
     @visibleForTesting WebKitProxy webKitProxy = const WebKitProxy(),
-  }) : this(webKitProxy: webKitProxy);
+    Set<PlaybackMediaTypes> mediaTypesRequiringUserAction =
+        const <PlaybackMediaTypes>{
+      PlaybackMediaTypes.audio,
+      PlaybackMediaTypes.video,
+    },
+    bool allowsInlineMediaPlayback = false,
+  }) : this(
+          webKitProxy: webKitProxy,
+          mediaTypesRequiringUserAction: mediaTypesRequiringUserAction,
+          allowsInlineMediaPlayback: allowsInlineMediaPlayback,
+        );
 
   final WKWebViewConfiguration _configuration;
 
+  /// Media types that require a user gesture to begin playing.
+  ///
+  /// Defaults to include [PlaybackMediaTypes.audio] and
+  /// [PlaybackMediaTypes.video].
+  final Set<PlaybackMediaTypes> mediaTypesRequiringUserAction;
+
+  /// Whether inline playback of HTML5 videos is allowed.
+  ///
+  /// Defaults to false.
+  final bool allowsInlineMediaPlayback;
+
   /// Handles constructing objects and calling static methods for the WebKit
   /// native library.
   @visibleForTesting
@@ -71,10 +132,12 @@
         NSObject object,
         Map<NSKeyValueChangeKey, Object?> change,
       ) {
-        if (weakReference.target?._onProgress != null) {
+        final ProgressCallback? progressCallback =
+            weakReference.target?._currentNavigationDelegate?._onProgress;
+        if (progressCallback != null) {
           final double progress =
               change[NSKeyValueChangeKey.newValue]! as double;
-          weakReference.target!._onProgress!((progress * 100).round());
+          progressCallback((progress * 100).round());
         }
       },
     );
@@ -84,7 +147,7 @@
       <String, WebKitJavaScriptChannelParams>{};
 
   bool _zoomEnabled = true;
-  void Function(int progress)? _onProgress;
+  WebKitNavigationDelegate? _currentNavigationDelegate;
 
   WebKitWebViewControllerCreationParams get _webKitParams =>
       params as WebKitWebViewControllerCreationParams;
@@ -215,7 +278,7 @@
   }
 
   @override
-  Future<String> runJavaScriptReturningResult(String javaScript) async {
+  Future<Object> runJavaScriptReturningResult(String javaScript) async {
     final Object? result = await _webView.evaluateJavaScript(javaScript);
     if (result == null) {
       throw ArgumentError(
@@ -223,12 +286,7 @@
         'Use `runJavascript` when expecting a null return value.',
       );
     }
-    return result.toString();
-  }
-
-  /// Controls whether inline playback of HTML5 videos is allowed.
-  Future<void> setAllowsInlineMediaPlayback(bool allow) {
-    return _webView.configuration.setAllowsInlineMediaPlayback(allow);
+    return result;
   }
 
   @override
@@ -251,25 +309,23 @@
   }
 
   @override
-  Future<Point<int>> getScrollPosition() async {
+  Future<Offset> getScrollPosition() async {
     final Point<double> offset = await _webView.scrollView.getContentOffset();
-    return Point<int>(offset.x.round(), offset.y.round());
+    return Offset(offset.x, offset.y);
   }
 
-  // TODO(bparrishMines): This is unique to iOS. Override should be removed if
-  // this is removed from the platform interface before webview_flutter version
-  // 4.0.0.
-  @override
-  Future<void> enableGestureNavigation(bool enabled) {
+  /// Whether horizontal swipe gestures trigger page navigation.
+  Future<void> setAllowsBackForwardNavigationGestures(bool enabled) {
     return _webView.setAllowsBackForwardNavigationGestures(enabled);
   }
 
   @override
   Future<void> setBackgroundColor(Color color) {
     return Future.wait(<Future<void>>[
-      _webView.scrollView.setBackgroundColor(color),
       _webView.setOpaque(false),
       _webView.setBackgroundColor(Colors.transparent),
+      // This method must be called last.
+      _webView.scrollView.setBackgroundColor(color),
     ]);
   }
 
@@ -306,8 +362,11 @@
   Future<void> setPlatformNavigationDelegate(
     covariant WebKitNavigationDelegate handler,
   ) {
-    _onProgress = handler._onProgress;
-    return _webView.setNavigationDelegate(handler._navigationDelegate);
+    _currentNavigationDelegate = handler;
+    return Future.wait(<Future<void>>[
+      _webView.setUIDelegate(handler._uiDelegate),
+      _webView.setNavigationDelegate(handler._navigationDelegate)
+    ]);
   }
 
   Future<void> _disableZoom() {
@@ -441,6 +500,7 @@
   @override
   Widget build(BuildContext context) {
     return UiKitView(
+      key: _webKitParams.key,
       viewType: 'plugins.flutter.io/webview',
       onPlatformViewCreated: (_) {},
       layoutDirection: params.layoutDirection,
@@ -454,11 +514,12 @@
 
 /// An implementation of [WebResourceError] with the WebKit API.
 class WebKitWebResourceError extends WebResourceError {
-  WebKitWebResourceError._(this._nsError)
+  WebKitWebResourceError._(this._nsError, {required bool isForMainFrame})
       : super(
           errorCode: _nsError.code,
           description: _nsError.localizedDescription,
           errorType: _toWebResourceErrorType(_nsError.code),
+          isForMainFrame: isForMainFrame,
         );
 
   static WebResourceErrorType? _toWebResourceErrorType(int code) {
@@ -518,9 +579,10 @@
                 .fromPlatformNavigationDelegateCreationParams(params)) {
     final WeakReference<WebKitNavigationDelegate> weakThis =
         WeakReference<WebKitNavigationDelegate>(this);
-    _navigationDelegate = (params as WebKitNavigationDelegateCreationParams)
-        .webKitProxy
-        .createNavigationDelegate(
+    _navigationDelegate =
+        (this.params as WebKitNavigationDelegateCreationParams)
+            .webKitProxy
+            .createNavigationDelegate(
       didFinishNavigation: (WKWebView webView, String? url) {
         if (weakThis.target?._onPageFinished != null) {
           weakThis.target!._onPageFinished!(url ?? '');
@@ -536,27 +598,31 @@
         WKNavigationAction action,
       ) async {
         if (weakThis.target?._onNavigationRequest != null) {
-          final bool allow = await weakThis.target!._onNavigationRequest!(
+          final NavigationDecision decision =
+              await weakThis.target!._onNavigationRequest!(NavigationRequest(
             url: action.request.url,
-            isForMainFrame: action.targetFrame.isMainFrame,
-          );
-          return allow
-              ? WKNavigationActionPolicy.allow
-              : WKNavigationActionPolicy.cancel;
+            isMainFrame: action.targetFrame.isMainFrame,
+          ));
+          switch (decision) {
+            case NavigationDecision.prevent:
+              return WKNavigationActionPolicy.cancel;
+            case NavigationDecision.navigate:
+              return WKNavigationActionPolicy.allow;
+          }
         }
         return WKNavigationActionPolicy.allow;
       },
       didFailNavigation: (WKWebView webView, NSError error) {
         if (weakThis.target?._onWebResourceError != null) {
           weakThis.target!._onWebResourceError!(
-            WebKitWebResourceError._(error),
+            WebKitWebResourceError._(error, isForMainFrame: true),
           );
         }
       },
       didFailProvisionalNavigation: (WKWebView webView, NSError error) {
         if (weakThis.target?._onWebResourceError != null) {
           weakThis.target!._onWebResourceError!(
-            WebKitWebResourceError._(error),
+            WebKitWebResourceError._(error, isForMainFrame: true),
           );
         }
       },
@@ -570,51 +636,65 @@
                 domain: 'WKErrorDomain',
                 localizedDescription: '',
               ),
+              isForMainFrame: true,
             ),
           );
         }
       },
     );
+
+    _uiDelegate = (this.params as WebKitNavigationDelegateCreationParams)
+        .webKitProxy
+        .createUIDelegate(
+      onCreateWebView: (
+        WKWebView webView,
+        WKWebViewConfiguration configuration,
+        WKNavigationAction navigationAction,
+      ) {
+        if (!navigationAction.targetFrame.isMainFrame) {
+          webView.loadRequest(navigationAction.request);
+        }
+      },
+    );
   }
 
   // Used to set `WKWebView.setNavigationDelegate` in `WebKitWebViewController`.
   late final WKNavigationDelegate _navigationDelegate;
 
-  void Function(String url)? _onPageFinished;
-  void Function(String url)? _onPageStarted;
-  void Function(int progress)? _onProgress;
-  void Function(WebResourceError error)? _onWebResourceError;
-  FutureOr<bool> Function({required String url, required bool isForMainFrame})?
-      _onNavigationRequest;
+  // Used to set `WKWebView.setUIDelegate` in `WebKitWebViewController`.
+  late final WKUIDelegate _uiDelegate;
+
+  PageEventCallback? _onPageFinished;
+  PageEventCallback? _onPageStarted;
+  ProgressCallback? _onProgress;
+  WebResourceErrorCallback? _onWebResourceError;
+  NavigationRequestCallback? _onNavigationRequest;
 
   @override
-  Future<void> setOnPageFinished(
-    void Function(String url) onPageFinished,
-  ) async {
+  Future<void> setOnPageFinished(PageEventCallback onPageFinished) async {
     _onPageFinished = onPageFinished;
   }
 
   @override
-  Future<void> setOnPageStarted(void Function(String url) onPageStarted) async {
+  Future<void> setOnPageStarted(PageEventCallback onPageStarted) async {
     _onPageStarted = onPageStarted;
   }
 
   @override
-  Future<void> setOnProgress(void Function(int progress) onProgress) async {
+  Future<void> setOnProgress(ProgressCallback onProgress) async {
     _onProgress = onProgress;
   }
 
   @override
   Future<void> setOnWebResourceError(
-    void Function(WebResourceError error) onWebResourceError,
+    WebResourceErrorCallback onWebResourceError,
   ) async {
     _onWebResourceError = onWebResourceError;
   }
 
   @override
   Future<void> setOnNavigationRequest(
-    FutureOr<bool> Function({required String url, required bool isForMainFrame})
-        onNavigationRequest,
+    NavigationRequestCallback onNavigationRequest,
   ) async {
     _onNavigationRequest = onNavigationRequest;
   }
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/lib/src/v4/src/webkit_webview_cookie_manager.dart b/packages/webview_flutter/webview_flutter_wkwebview/lib/src/webkit_webview_cookie_manager.dart
similarity index 94%
rename from packages/webview_flutter/webview_flutter_wkwebview/lib/src/v4/src/webkit_webview_cookie_manager.dart
rename to packages/webview_flutter/webview_flutter_wkwebview/lib/src/webkit_webview_cookie_manager.dart
index 423b3bd..00e9701 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/lib/src/v4/src/webkit_webview_cookie_manager.dart
+++ b/packages/webview_flutter/webview_flutter_wkwebview/lib/src/webkit_webview_cookie_manager.dart
@@ -3,10 +3,10 @@
 // found in the LICENSE file.
 
 import 'package:flutter/foundation.dart';
-import 'package:webview_flutter_platform_interface/v4/webview_flutter_platform_interface.dart';
+import 'package:webview_flutter_platform_interface/webview_flutter_platform_interface.dart';
 
-import '../../foundation/foundation.dart';
-import '../../web_kit/web_kit.dart';
+import 'foundation/foundation.dart';
+import 'web_kit/web_kit.dart';
 import 'webkit_proxy.dart';
 
 /// Object specifying creation parameters for a [WebKitWebViewCookieManager].
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/lib/src/v4/src/webkit_webview_platform.dart b/packages/webview_flutter/webview_flutter_wkwebview/lib/src/webkit_webview_platform.dart
similarity index 80%
rename from packages/webview_flutter/webview_flutter_wkwebview/lib/src/v4/src/webkit_webview_platform.dart
rename to packages/webview_flutter/webview_flutter_wkwebview/lib/src/webkit_webview_platform.dart
index 13116bb..018d7c0 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/lib/src/v4/src/webkit_webview_platform.dart
+++ b/packages/webview_flutter/webview_flutter_wkwebview/lib/src/webkit_webview_platform.dart
@@ -2,13 +2,18 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import 'package:webview_flutter_platform_interface/v4/webview_flutter_platform_interface.dart';
+import 'package:webview_flutter_platform_interface/webview_flutter_platform_interface.dart';
 
 import 'webkit_webview_controller.dart';
 import 'webkit_webview_cookie_manager.dart';
 
 /// Implementation of [WebViewPlatform] using the WebKit API.
 class WebKitWebViewPlatform extends WebViewPlatform {
+  /// Registers this class as the default instance of [WebViewPlatform].
+  static void registerWith() {
+    WebViewPlatform.instance = WebKitWebViewPlatform();
+  }
+
   @override
   WebKitWebViewController createPlatformWebViewController(
     PlatformWebViewControllerCreationParams params,
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/lib/src/webview_flutter_wkwebview_legacy.dart b/packages/webview_flutter/webview_flutter_wkwebview/lib/src/webview_flutter_wkwebview_legacy.dart
new file mode 100644
index 0000000..f4a2ad1
--- /dev/null
+++ b/packages/webview_flutter/webview_flutter_wkwebview/lib/src/webview_flutter_wkwebview_legacy.dart
@@ -0,0 +1,6 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+export 'legacy/webview_cupertino.dart';
+export 'legacy/wkwebview_cookie_manager.dart';
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/lib/webview_flutter_wkwebview.dart b/packages/webview_flutter/webview_flutter_wkwebview/lib/webview_flutter_wkwebview.dart
index f647ab3..f54fb73 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/lib/webview_flutter_wkwebview.dart
+++ b/packages/webview_flutter/webview_flutter_wkwebview/lib/webview_flutter_wkwebview.dart
@@ -2,5 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-export 'src/webview_cupertino.dart';
-export 'src/wkwebview_cookie_manager.dart';
+library webview_flutter_wkwebview;
+
+export 'src/webkit_webview_controller.dart';
+export 'src/webkit_webview_cookie_manager.dart';
+export 'src/webkit_webview_platform.dart';
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/pubspec.yaml b/packages/webview_flutter/webview_flutter_wkwebview/pubspec.yaml
index 3de385f..bf443e8 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/pubspec.yaml
+++ b/packages/webview_flutter/webview_flutter_wkwebview/pubspec.yaml
@@ -2,7 +2,7 @@
 description: A Flutter plugin that provides a WebView widget based on Apple's WKWebView control.
 repository: https://github.com/flutter/plugins/tree/main/packages/webview_flutter/webview_flutter_wkwebview
 issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+webview%22
-version: 2.9.5
+version: 3.0.0
 
 environment:
   sdk: ">=2.17.0 <3.0.0"
@@ -14,12 +14,13 @@
     platforms:
       ios:
         pluginClass: FLTWebViewFlutterPlugin
+        dartPluginClass: WebKitWebViewPlatform
 
 dependencies:
   flutter:
     sdk: flutter
   path: ^1.8.0
-  webview_flutter_platform_interface: ^1.9.3
+  webview_flutter_platform_interface: ^2.0.0
 
 dev_dependencies:
   build_runner: ^2.1.5
@@ -27,5 +28,5 @@
     sdk: flutter
   flutter_test:
     sdk: flutter
-  mockito: ^5.1.0
+  mockito: ^5.3.2
   pigeon: ^3.0.3
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/test/src/web_kit_cookie_manager_test.dart b/packages/webview_flutter/webview_flutter_wkwebview/test/legacy/web_kit_cookie_manager_test.dart
similarity index 93%
rename from packages/webview_flutter/webview_flutter_wkwebview/test/src/web_kit_cookie_manager_test.dart
rename to packages/webview_flutter/webview_flutter_wkwebview/test/legacy/web_kit_cookie_manager_test.dart
index 73d8c8f..4f775df 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/test/src/web_kit_cookie_manager_test.dart
+++ b/packages/webview_flutter/webview_flutter_wkwebview/test/legacy/web_kit_cookie_manager_test.dart
@@ -5,10 +5,10 @@
 import 'package:flutter_test/flutter_test.dart';
 import 'package:mockito/annotations.dart';
 import 'package:mockito/mockito.dart';
-import 'package:webview_flutter_platform_interface/webview_flutter_platform_interface.dart';
+import 'package:webview_flutter_platform_interface/src/webview_flutter_platform_interface_legacy.dart';
 import 'package:webview_flutter_wkwebview/src/foundation/foundation.dart';
+import 'package:webview_flutter_wkwebview/src/legacy/wkwebview_cookie_manager.dart';
 import 'package:webview_flutter_wkwebview/src/web_kit/web_kit.dart';
-import 'package:webview_flutter_wkwebview/src/wkwebview_cookie_manager.dart';
 
 import 'web_kit_cookie_manager_test.mocks.dart';
 
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/test/legacy/web_kit_cookie_manager_test.mocks.dart b/packages/webview_flutter/webview_flutter_wkwebview/test/legacy/web_kit_cookie_manager_test.mocks.dart
new file mode 100644
index 0000000..860e8db
--- /dev/null
+++ b/packages/webview_flutter/webview_flutter_wkwebview/test/legacy/web_kit_cookie_manager_test.mocks.dart
@@ -0,0 +1,191 @@
+// Mocks generated by Mockito 5.3.2 from annotations
+// in webview_flutter_wkwebview/test/legacy/web_kit_cookie_manager_test.dart.
+// Do not manually edit this file.
+
+// ignore_for_file: no_leading_underscores_for_library_prefixes
+import 'dart:async' as _i3;
+
+import 'package:mockito/mockito.dart' as _i1;
+import 'package:webview_flutter_wkwebview/src/foundation/foundation.dart'
+    as _i4;
+import 'package:webview_flutter_wkwebview/src/web_kit/web_kit.dart' as _i2;
+
+// ignore_for_file: type=lint
+// ignore_for_file: avoid_redundant_argument_values
+// ignore_for_file: avoid_setters_without_getters
+// ignore_for_file: comment_references
+// ignore_for_file: implementation_imports
+// ignore_for_file: invalid_use_of_visible_for_testing_member
+// ignore_for_file: prefer_const_constructors
+// ignore_for_file: unnecessary_parenthesis
+// ignore_for_file: camel_case_types
+// ignore_for_file: subtype_of_sealed_class
+
+class _FakeWKHttpCookieStore_0 extends _i1.SmartFake
+    implements _i2.WKHttpCookieStore {
+  _FakeWKHttpCookieStore_0(
+    Object parent,
+    Invocation parentInvocation,
+  ) : super(
+          parent,
+          parentInvocation,
+        );
+}
+
+class _FakeWKWebsiteDataStore_1 extends _i1.SmartFake
+    implements _i2.WKWebsiteDataStore {
+  _FakeWKWebsiteDataStore_1(
+    Object parent,
+    Invocation parentInvocation,
+  ) : super(
+          parent,
+          parentInvocation,
+        );
+}
+
+/// A class which mocks [WKHttpCookieStore].
+///
+/// See the documentation for Mockito's code generation for more information.
+// ignore: must_be_immutable
+class MockWKHttpCookieStore extends _i1.Mock implements _i2.WKHttpCookieStore {
+  MockWKHttpCookieStore() {
+    _i1.throwOnMissingStub(this);
+  }
+
+  @override
+  _i3.Future<void> setCookie(_i4.NSHttpCookie? cookie) => (super.noSuchMethod(
+        Invocation.method(
+          #setCookie,
+          [cookie],
+        ),
+        returnValue: _i3.Future<void>.value(),
+        returnValueForMissingStub: _i3.Future<void>.value(),
+      ) as _i3.Future<void>);
+  @override
+  _i2.WKHttpCookieStore copy() => (super.noSuchMethod(
+        Invocation.method(
+          #copy,
+          [],
+        ),
+        returnValue: _FakeWKHttpCookieStore_0(
+          this,
+          Invocation.method(
+            #copy,
+            [],
+          ),
+        ),
+      ) as _i2.WKHttpCookieStore);
+  @override
+  _i3.Future<void> addObserver(
+    _i4.NSObject? observer, {
+    required String? keyPath,
+    required Set<_i4.NSKeyValueObservingOptions>? options,
+  }) =>
+      (super.noSuchMethod(
+        Invocation.method(
+          #addObserver,
+          [observer],
+          {
+            #keyPath: keyPath,
+            #options: options,
+          },
+        ),
+        returnValue: _i3.Future<void>.value(),
+        returnValueForMissingStub: _i3.Future<void>.value(),
+      ) as _i3.Future<void>);
+  @override
+  _i3.Future<void> removeObserver(
+    _i4.NSObject? observer, {
+    required String? keyPath,
+  }) =>
+      (super.noSuchMethod(
+        Invocation.method(
+          #removeObserver,
+          [observer],
+          {#keyPath: keyPath},
+        ),
+        returnValue: _i3.Future<void>.value(),
+        returnValueForMissingStub: _i3.Future<void>.value(),
+      ) as _i3.Future<void>);
+}
+
+/// A class which mocks [WKWebsiteDataStore].
+///
+/// See the documentation for Mockito's code generation for more information.
+// ignore: must_be_immutable
+class MockWKWebsiteDataStore extends _i1.Mock
+    implements _i2.WKWebsiteDataStore {
+  MockWKWebsiteDataStore() {
+    _i1.throwOnMissingStub(this);
+  }
+
+  @override
+  _i2.WKHttpCookieStore get httpCookieStore => (super.noSuchMethod(
+        Invocation.getter(#httpCookieStore),
+        returnValue: _FakeWKHttpCookieStore_0(
+          this,
+          Invocation.getter(#httpCookieStore),
+        ),
+      ) as _i2.WKHttpCookieStore);
+  @override
+  _i3.Future<bool> removeDataOfTypes(
+    Set<_i2.WKWebsiteDataType>? dataTypes,
+    DateTime? since,
+  ) =>
+      (super.noSuchMethod(
+        Invocation.method(
+          #removeDataOfTypes,
+          [
+            dataTypes,
+            since,
+          ],
+        ),
+        returnValue: _i3.Future<bool>.value(false),
+      ) as _i3.Future<bool>);
+  @override
+  _i2.WKWebsiteDataStore copy() => (super.noSuchMethod(
+        Invocation.method(
+          #copy,
+          [],
+        ),
+        returnValue: _FakeWKWebsiteDataStore_1(
+          this,
+          Invocation.method(
+            #copy,
+            [],
+          ),
+        ),
+      ) as _i2.WKWebsiteDataStore);
+  @override
+  _i3.Future<void> addObserver(
+    _i4.NSObject? observer, {
+    required String? keyPath,
+    required Set<_i4.NSKeyValueObservingOptions>? options,
+  }) =>
+      (super.noSuchMethod(
+        Invocation.method(
+          #addObserver,
+          [observer],
+          {
+            #keyPath: keyPath,
+            #options: options,
+          },
+        ),
+        returnValue: _i3.Future<void>.value(),
+        returnValueForMissingStub: _i3.Future<void>.value(),
+      ) as _i3.Future<void>);
+  @override
+  _i3.Future<void> removeObserver(
+    _i4.NSObject? observer, {
+    required String? keyPath,
+  }) =>
+      (super.noSuchMethod(
+        Invocation.method(
+          #removeObserver,
+          [observer],
+          {#keyPath: keyPath},
+        ),
+        returnValue: _i3.Future<void>.value(),
+        returnValueForMissingStub: _i3.Future<void>.value(),
+      ) as _i3.Future<void>);
+}
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/test/src/web_kit_webview_widget_test.dart b/packages/webview_flutter/webview_flutter_wkwebview/test/legacy/web_kit_webview_widget_test.dart
similarity index 98%
rename from packages/webview_flutter/webview_flutter_wkwebview/test/src/web_kit_webview_widget_test.dart
rename to packages/webview_flutter/webview_flutter_wkwebview/test/legacy/web_kit_webview_widget_test.dart
index 9df910f..b64c142 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/test/src/web_kit_webview_widget_test.dart
+++ b/packages/webview_flutter/webview_flutter_wkwebview/test/legacy/web_kit_webview_widget_test.dart
@@ -12,11 +12,11 @@
 import 'package:flutter_test/flutter_test.dart';
 import 'package:mockito/annotations.dart';
 import 'package:mockito/mockito.dart';
-import 'package:webview_flutter_platform_interface/webview_flutter_platform_interface.dart';
+import 'package:webview_flutter_platform_interface/src/webview_flutter_platform_interface_legacy.dart';
 import 'package:webview_flutter_wkwebview/src/foundation/foundation.dart';
+import 'package:webview_flutter_wkwebview/src/legacy/web_kit_webview_widget.dart';
 import 'package:webview_flutter_wkwebview/src/ui_kit/ui_kit.dart';
 import 'package:webview_flutter_wkwebview/src/web_kit/web_kit.dart';
-import 'package:webview_flutter_wkwebview/src/web_kit_webview_widget.dart';
 
 import 'web_kit_webview_widget_test.mocks.dart';
 
@@ -363,11 +363,6 @@
         testWidgets(
           'enabling zoom removes script',
           (WidgetTester tester) async {
-            when(mockWebViewWidgetProxy.createScriptMessageHandler())
-                .thenReturn(
-              MockWKScriptMessageHandler(),
-            );
-
             await buildWidget(
               tester,
               creationParams: CreationParams(
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/test/legacy/web_kit_webview_widget_test.mocks.dart b/packages/webview_flutter/webview_flutter_wkwebview/test/legacy/web_kit_webview_widget_test.mocks.dart
new file mode 100644
index 0000000..1680997
--- /dev/null
+++ b/packages/webview_flutter/webview_flutter_wkwebview/test/legacy/web_kit_webview_widget_test.mocks.dart
@@ -0,0 +1,1300 @@
+// Mocks generated by Mockito 5.3.2 from annotations
+// in webview_flutter_wkwebview/test/legacy/web_kit_webview_widget_test.dart.
+// Do not manually edit this file.
+
+// ignore_for_file: no_leading_underscores_for_library_prefixes
+import 'dart:async' as _i5;
+import 'dart:math' as _i2;
+import 'dart:ui' as _i6;
+
+import 'package:mockito/mockito.dart' as _i1;
+import 'package:webview_flutter_platform_interface/src/legacy/types/javascript_channel.dart'
+    as _i9;
+import 'package:webview_flutter_platform_interface/src/legacy/types/types.dart'
+    as _i10;
+import 'package:webview_flutter_platform_interface/src/webview_flutter_platform_interface_legacy.dart'
+    as _i8;
+import 'package:webview_flutter_wkwebview/src/foundation/foundation.dart'
+    as _i7;
+import 'package:webview_flutter_wkwebview/src/legacy/web_kit_webview_widget.dart'
+    as _i11;
+import 'package:webview_flutter_wkwebview/src/ui_kit/ui_kit.dart' as _i3;
+import 'package:webview_flutter_wkwebview/src/web_kit/web_kit.dart' as _i4;
+
+// ignore_for_file: type=lint
+// ignore_for_file: avoid_redundant_argument_values
+// ignore_for_file: avoid_setters_without_getters
+// ignore_for_file: comment_references
+// ignore_for_file: implementation_imports
+// ignore_for_file: invalid_use_of_visible_for_testing_member
+// ignore_for_file: prefer_const_constructors
+// ignore_for_file: unnecessary_parenthesis
+// ignore_for_file: camel_case_types
+// ignore_for_file: subtype_of_sealed_class
+
+class _FakePoint_0<T extends num> extends _i1.SmartFake
+    implements _i2.Point<T> {
+  _FakePoint_0(
+    Object parent,
+    Invocation parentInvocation,
+  ) : super(
+          parent,
+          parentInvocation,
+        );
+}
+
+class _FakeUIScrollView_1 extends _i1.SmartFake implements _i3.UIScrollView {
+  _FakeUIScrollView_1(
+    Object parent,
+    Invocation parentInvocation,
+  ) : super(
+          parent,
+          parentInvocation,
+        );
+}
+
+class _FakeWKNavigationDelegate_2 extends _i1.SmartFake
+    implements _i4.WKNavigationDelegate {
+  _FakeWKNavigationDelegate_2(
+    Object parent,
+    Invocation parentInvocation,
+  ) : super(
+          parent,
+          parentInvocation,
+        );
+}
+
+class _FakeWKPreferences_3 extends _i1.SmartFake implements _i4.WKPreferences {
+  _FakeWKPreferences_3(
+    Object parent,
+    Invocation parentInvocation,
+  ) : super(
+          parent,
+          parentInvocation,
+        );
+}
+
+class _FakeWKScriptMessageHandler_4 extends _i1.SmartFake
+    implements _i4.WKScriptMessageHandler {
+  _FakeWKScriptMessageHandler_4(
+    Object parent,
+    Invocation parentInvocation,
+  ) : super(
+          parent,
+          parentInvocation,
+        );
+}
+
+class _FakeWKWebViewConfiguration_5 extends _i1.SmartFake
+    implements _i4.WKWebViewConfiguration {
+  _FakeWKWebViewConfiguration_5(
+    Object parent,
+    Invocation parentInvocation,
+  ) : super(
+          parent,
+          parentInvocation,
+        );
+}
+
+class _FakeWKWebView_6 extends _i1.SmartFake implements _i4.WKWebView {
+  _FakeWKWebView_6(
+    Object parent,
+    Invocation parentInvocation,
+  ) : super(
+          parent,
+          parentInvocation,
+        );
+}
+
+class _FakeWKUserContentController_7 extends _i1.SmartFake
+    implements _i4.WKUserContentController {
+  _FakeWKUserContentController_7(
+    Object parent,
+    Invocation parentInvocation,
+  ) : super(
+          parent,
+          parentInvocation,
+        );
+}
+
+class _FakeWKWebsiteDataStore_8 extends _i1.SmartFake
+    implements _i4.WKWebsiteDataStore {
+  _FakeWKWebsiteDataStore_8(
+    Object parent,
+    Invocation parentInvocation,
+  ) : super(
+          parent,
+          parentInvocation,
+        );
+}
+
+class _FakeWKHttpCookieStore_9 extends _i1.SmartFake
+    implements _i4.WKHttpCookieStore {
+  _FakeWKHttpCookieStore_9(
+    Object parent,
+    Invocation parentInvocation,
+  ) : super(
+          parent,
+          parentInvocation,
+        );
+}
+
+class _FakeWKUIDelegate_10 extends _i1.SmartFake implements _i4.WKUIDelegate {
+  _FakeWKUIDelegate_10(
+    Object parent,
+    Invocation parentInvocation,
+  ) : super(
+          parent,
+          parentInvocation,
+        );
+}
+
+/// A class which mocks [UIScrollView].
+///
+/// See the documentation for Mockito's code generation for more information.
+// ignore: must_be_immutable
+class MockUIScrollView extends _i1.Mock implements _i3.UIScrollView {
+  MockUIScrollView() {
+    _i1.throwOnMissingStub(this);
+  }
+
+  @override
+  _i5.Future<_i2.Point<double>> getContentOffset() => (super.noSuchMethod(
+        Invocation.method(
+          #getContentOffset,
+          [],
+        ),
+        returnValue: _i5.Future<_i2.Point<double>>.value(_FakePoint_0<double>(
+          this,
+          Invocation.method(
+            #getContentOffset,
+            [],
+          ),
+        )),
+      ) as _i5.Future<_i2.Point<double>>);
+  @override
+  _i5.Future<void> scrollBy(_i2.Point<double>? offset) => (super.noSuchMethod(
+        Invocation.method(
+          #scrollBy,
+          [offset],
+        ),
+        returnValue: _i5.Future<void>.value(),
+        returnValueForMissingStub: _i5.Future<void>.value(),
+      ) as _i5.Future<void>);
+  @override
+  _i5.Future<void> setContentOffset(_i2.Point<double>? offset) =>
+      (super.noSuchMethod(
+        Invocation.method(
+          #setContentOffset,
+          [offset],
+        ),
+        returnValue: _i5.Future<void>.value(),
+        returnValueForMissingStub: _i5.Future<void>.value(),
+      ) as _i5.Future<void>);
+  @override
+  _i3.UIScrollView copy() => (super.noSuchMethod(
+        Invocation.method(
+          #copy,
+          [],
+        ),
+        returnValue: _FakeUIScrollView_1(
+          this,
+          Invocation.method(
+            #copy,
+            [],
+          ),
+        ),
+      ) as _i3.UIScrollView);
+  @override
+  _i5.Future<void> setBackgroundColor(_i6.Color? color) => (super.noSuchMethod(
+        Invocation.method(
+          #setBackgroundColor,
+          [color],
+        ),
+        returnValue: _i5.Future<void>.value(),
+        returnValueForMissingStub: _i5.Future<void>.value(),
+      ) as _i5.Future<void>);
+  @override
+  _i5.Future<void> setOpaque(bool? opaque) => (super.noSuchMethod(
+        Invocation.method(
+          #setOpaque,
+          [opaque],
+        ),
+        returnValue: _i5.Future<void>.value(),
+        returnValueForMissingStub: _i5.Future<void>.value(),
+      ) as _i5.Future<void>);
+  @override
+  _i5.Future<void> addObserver(
+    _i7.NSObject? observer, {
+    required String? keyPath,
+    required Set<_i7.NSKeyValueObservingOptions>? options,
+  }) =>
+      (super.noSuchMethod(
+        Invocation.method(
+          #addObserver,
+          [observer],
+          {
+            #keyPath: keyPath,
+            #options: options,
+          },
+        ),
+        returnValue: _i5.Future<void>.value(),
+        returnValueForMissingStub: _i5.Future<void>.value(),
+      ) as _i5.Future<void>);
+  @override
+  _i5.Future<void> removeObserver(
+    _i7.NSObject? observer, {
+    required String? keyPath,
+  }) =>
+      (super.noSuchMethod(
+        Invocation.method(
+          #removeObserver,
+          [observer],
+          {#keyPath: keyPath},
+        ),
+        returnValue: _i5.Future<void>.value(),
+        returnValueForMissingStub: _i5.Future<void>.value(),
+      ) as _i5.Future<void>);
+}
+
+/// A class which mocks [WKNavigationDelegate].
+///
+/// See the documentation for Mockito's code generation for more information.
+// ignore: must_be_immutable
+class MockWKNavigationDelegate extends _i1.Mock
+    implements _i4.WKNavigationDelegate {
+  MockWKNavigationDelegate() {
+    _i1.throwOnMissingStub(this);
+  }
+
+  @override
+  _i4.WKNavigationDelegate copy() => (super.noSuchMethod(
+        Invocation.method(
+          #copy,
+          [],
+        ),
+        returnValue: _FakeWKNavigationDelegate_2(
+          this,
+          Invocation.method(
+            #copy,
+            [],
+          ),
+        ),
+      ) as _i4.WKNavigationDelegate);
+  @override
+  _i5.Future<void> addObserver(
+    _i7.NSObject? observer, {
+    required String? keyPath,
+    required Set<_i7.NSKeyValueObservingOptions>? options,
+  }) =>
+      (super.noSuchMethod(
+        Invocation.method(
+          #addObserver,
+          [observer],
+          {
+            #keyPath: keyPath,
+            #options: options,
+          },
+        ),
+        returnValue: _i5.Future<void>.value(),
+        returnValueForMissingStub: _i5.Future<void>.value(),
+      ) as _i5.Future<void>);
+  @override
+  _i5.Future<void> removeObserver(
+    _i7.NSObject? observer, {
+    required String? keyPath,
+  }) =>
+      (super.noSuchMethod(
+        Invocation.method(
+          #removeObserver,
+          [observer],
+          {#keyPath: keyPath},
+        ),
+        returnValue: _i5.Future<void>.value(),
+        returnValueForMissingStub: _i5.Future<void>.value(),
+      ) as _i5.Future<void>);
+}
+
+/// A class which mocks [WKPreferences].
+///
+/// See the documentation for Mockito's code generation for more information.
+// ignore: must_be_immutable
+class MockWKPreferences extends _i1.Mock implements _i4.WKPreferences {
+  MockWKPreferences() {
+    _i1.throwOnMissingStub(this);
+  }
+
+  @override
+  _i5.Future<void> setJavaScriptEnabled(bool? enabled) => (super.noSuchMethod(
+        Invocation.method(
+          #setJavaScriptEnabled,
+          [enabled],
+        ),
+        returnValue: _i5.Future<void>.value(),
+        returnValueForMissingStub: _i5.Future<void>.value(),
+      ) as _i5.Future<void>);
+  @override
+  _i4.WKPreferences copy() => (super.noSuchMethod(
+        Invocation.method(
+          #copy,
+          [],
+        ),
+        returnValue: _FakeWKPreferences_3(
+          this,
+          Invocation.method(
+            #copy,
+            [],
+          ),
+        ),
+      ) as _i4.WKPreferences);
+  @override
+  _i5.Future<void> addObserver(
+    _i7.NSObject? observer, {
+    required String? keyPath,
+    required Set<_i7.NSKeyValueObservingOptions>? options,
+  }) =>
+      (super.noSuchMethod(
+        Invocation.method(
+          #addObserver,
+          [observer],
+          {
+            #keyPath: keyPath,
+            #options: options,
+          },
+        ),
+        returnValue: _i5.Future<void>.value(),
+        returnValueForMissingStub: _i5.Future<void>.value(),
+      ) as _i5.Future<void>);
+  @override
+  _i5.Future<void> removeObserver(
+    _i7.NSObject? observer, {
+    required String? keyPath,
+  }) =>
+      (super.noSuchMethod(
+        Invocation.method(
+          #removeObserver,
+          [observer],
+          {#keyPath: keyPath},
+        ),
+        returnValue: _i5.Future<void>.value(),
+        returnValueForMissingStub: _i5.Future<void>.value(),
+      ) as _i5.Future<void>);
+}
+
+/// A class which mocks [WKScriptMessageHandler].
+///
+/// See the documentation for Mockito's code generation for more information.
+// ignore: must_be_immutable
+class MockWKScriptMessageHandler extends _i1.Mock
+    implements _i4.WKScriptMessageHandler {
+  MockWKScriptMessageHandler() {
+    _i1.throwOnMissingStub(this);
+  }
+
+  @override
+  void Function(
+    _i4.WKUserContentController,
+    _i4.WKScriptMessage,
+  ) get didReceiveScriptMessage => (super.noSuchMethod(
+        Invocation.getter(#didReceiveScriptMessage),
+        returnValue: (
+          _i4.WKUserContentController userContentController,
+          _i4.WKScriptMessage message,
+        ) {},
+      ) as void Function(
+        _i4.WKUserContentController,
+        _i4.WKScriptMessage,
+      ));
+  @override
+  _i4.WKScriptMessageHandler copy() => (super.noSuchMethod(
+        Invocation.method(
+          #copy,
+          [],
+        ),
+        returnValue: _FakeWKScriptMessageHandler_4(
+          this,
+          Invocation.method(
+            #copy,
+            [],
+          ),
+        ),
+      ) as _i4.WKScriptMessageHandler);
+  @override
+  _i5.Future<void> addObserver(
+    _i7.NSObject? observer, {
+    required String? keyPath,
+    required Set<_i7.NSKeyValueObservingOptions>? options,
+  }) =>
+      (super.noSuchMethod(
+        Invocation.method(
+          #addObserver,
+          [observer],
+          {
+            #keyPath: keyPath,
+            #options: options,
+          },
+        ),
+        returnValue: _i5.Future<void>.value(),
+        returnValueForMissingStub: _i5.Future<void>.value(),
+      ) as _i5.Future<void>);
+  @override
+  _i5.Future<void> removeObserver(
+    _i7.NSObject? observer, {
+    required String? keyPath,
+  }) =>
+      (super.noSuchMethod(
+        Invocation.method(
+          #removeObserver,
+          [observer],
+          {#keyPath: keyPath},
+        ),
+        returnValue: _i5.Future<void>.value(),
+        returnValueForMissingStub: _i5.Future<void>.value(),
+      ) as _i5.Future<void>);
+}
+
+/// A class which mocks [WKWebView].
+///
+/// See the documentation for Mockito's code generation for more information.
+// ignore: must_be_immutable
+class MockWKWebView extends _i1.Mock implements _i4.WKWebView {
+  MockWKWebView() {
+    _i1.throwOnMissingStub(this);
+  }
+
+  @override
+  _i4.WKWebViewConfiguration get configuration => (super.noSuchMethod(
+        Invocation.getter(#configuration),
+        returnValue: _FakeWKWebViewConfiguration_5(
+          this,
+          Invocation.getter(#configuration),
+        ),
+      ) as _i4.WKWebViewConfiguration);
+  @override
+  _i3.UIScrollView get scrollView => (super.noSuchMethod(
+        Invocation.getter(#scrollView),
+        returnValue: _FakeUIScrollView_1(
+          this,
+          Invocation.getter(#scrollView),
+        ),
+      ) as _i3.UIScrollView);
+  @override
+  _i5.Future<void> setUIDelegate(_i4.WKUIDelegate? delegate) =>
+      (super.noSuchMethod(
+        Invocation.method(
+          #setUIDelegate,
+          [delegate],
+        ),
+        returnValue: _i5.Future<void>.value(),
+        returnValueForMissingStub: _i5.Future<void>.value(),
+      ) as _i5.Future<void>);
+  @override
+  _i5.Future<void> setNavigationDelegate(_i4.WKNavigationDelegate? delegate) =>
+      (super.noSuchMethod(
+        Invocation.method(
+          #setNavigationDelegate,
+          [delegate],
+        ),
+        returnValue: _i5.Future<void>.value(),
+        returnValueForMissingStub: _i5.Future<void>.value(),
+      ) as _i5.Future<void>);
+  @override
+  _i5.Future<String?> getUrl() => (super.noSuchMethod(
+        Invocation.method(
+          #getUrl,
+          [],
+        ),
+        returnValue: _i5.Future<String?>.value(),
+      ) as _i5.Future<String?>);
+  @override
+  _i5.Future<double> getEstimatedProgress() => (super.noSuchMethod(
+        Invocation.method(
+          #getEstimatedProgress,
+          [],
+        ),
+        returnValue: _i5.Future<double>.value(0.0),
+      ) as _i5.Future<double>);
+  @override
+  _i5.Future<void> loadRequest(_i7.NSUrlRequest? request) =>
+      (super.noSuchMethod(
+        Invocation.method(
+          #loadRequest,
+          [request],
+        ),
+        returnValue: _i5.Future<void>.value(),
+        returnValueForMissingStub: _i5.Future<void>.value(),
+      ) as _i5.Future<void>);
+  @override
+  _i5.Future<void> loadHtmlString(
+    String? string, {
+    String? baseUrl,
+  }) =>
+      (super.noSuchMethod(
+        Invocation.method(
+          #loadHtmlString,
+          [string],
+          {#baseUrl: baseUrl},
+        ),
+        returnValue: _i5.Future<void>.value(),
+        returnValueForMissingStub: _i5.Future<void>.value(),
+      ) as _i5.Future<void>);
+  @override
+  _i5.Future<void> loadFileUrl(
+    String? url, {
+    required String? readAccessUrl,
+  }) =>
+      (super.noSuchMethod(
+        Invocation.method(
+          #loadFileUrl,
+          [url],
+          {#readAccessUrl: readAccessUrl},
+        ),
+        returnValue: _i5.Future<void>.value(),
+        returnValueForMissingStub: _i5.Future<void>.value(),
+      ) as _i5.Future<void>);
+  @override
+  _i5.Future<void> loadFlutterAsset(String? key) => (super.noSuchMethod(
+        Invocation.method(
+          #loadFlutterAsset,
+          [key],
+        ),
+        returnValue: _i5.Future<void>.value(),
+        returnValueForMissingStub: _i5.Future<void>.value(),
+      ) as _i5.Future<void>);
+  @override
+  _i5.Future<bool> canGoBack() => (super.noSuchMethod(
+        Invocation.method(
+          #canGoBack,
+          [],
+        ),
+        returnValue: _i5.Future<bool>.value(false),
+      ) as _i5.Future<bool>);
+  @override
+  _i5.Future<bool> canGoForward() => (super.noSuchMethod(
+        Invocation.method(
+          #canGoForward,
+          [],
+        ),
+        returnValue: _i5.Future<bool>.value(false),
+      ) as _i5.Future<bool>);
+  @override
+  _i5.Future<void> goBack() => (super.noSuchMethod(
+        Invocation.method(
+          #goBack,
+          [],
+        ),
+        returnValue: _i5.Future<void>.value(),
+        returnValueForMissingStub: _i5.Future<void>.value(),
+      ) as _i5.Future<void>);
+  @override
+  _i5.Future<void> goForward() => (super.noSuchMethod(
+        Invocation.method(
+          #goForward,
+          [],
+        ),
+        returnValue: _i5.Future<void>.value(),
+        returnValueForMissingStub: _i5.Future<void>.value(),
+      ) as _i5.Future<void>);
+  @override
+  _i5.Future<void> reload() => (super.noSuchMethod(
+        Invocation.method(
+          #reload,
+          [],
+        ),
+        returnValue: _i5.Future<void>.value(),
+        returnValueForMissingStub: _i5.Future<void>.value(),
+      ) as _i5.Future<void>);
+  @override
+  _i5.Future<String?> getTitle() => (super.noSuchMethod(
+        Invocation.method(
+          #getTitle,
+          [],
+        ),
+        returnValue: _i5.Future<String?>.value(),
+      ) as _i5.Future<String?>);
+  @override
+  _i5.Future<void> setAllowsBackForwardNavigationGestures(bool? allow) =>
+      (super.noSuchMethod(
+        Invocation.method(
+          #setAllowsBackForwardNavigationGestures,
+          [allow],
+        ),
+        returnValue: _i5.Future<void>.value(),
+        returnValueForMissingStub: _i5.Future<void>.value(),
+      ) as _i5.Future<void>);
+  @override
+  _i5.Future<void> setCustomUserAgent(String? userAgent) => (super.noSuchMethod(
+        Invocation.method(
+          #setCustomUserAgent,
+          [userAgent],
+        ),
+        returnValue: _i5.Future<void>.value(),
+        returnValueForMissingStub: _i5.Future<void>.value(),
+      ) as _i5.Future<void>);
+  @override
+  _i5.Future<Object?> evaluateJavaScript(String? javaScriptString) =>
+      (super.noSuchMethod(
+        Invocation.method(
+          #evaluateJavaScript,
+          [javaScriptString],
+        ),
+        returnValue: _i5.Future<Object?>.value(),
+      ) as _i5.Future<Object?>);
+  @override
+  _i4.WKWebView copy() => (super.noSuchMethod(
+        Invocation.method(
+          #copy,
+          [],
+        ),
+        returnValue: _FakeWKWebView_6(
+          this,
+          Invocation.method(
+            #copy,
+            [],
+          ),
+        ),
+      ) as _i4.WKWebView);
+  @override
+  _i5.Future<void> setBackgroundColor(_i6.Color? color) => (super.noSuchMethod(
+        Invocation.method(
+          #setBackgroundColor,
+          [color],
+        ),
+        returnValue: _i5.Future<void>.value(),
+        returnValueForMissingStub: _i5.Future<void>.value(),
+      ) as _i5.Future<void>);
+  @override
+  _i5.Future<void> setOpaque(bool? opaque) => (super.noSuchMethod(
+        Invocation.method(
+          #setOpaque,
+          [opaque],
+        ),
+        returnValue: _i5.Future<void>.value(),
+        returnValueForMissingStub: _i5.Future<void>.value(),
+      ) as _i5.Future<void>);
+  @override
+  _i5.Future<void> addObserver(
+    _i7.NSObject? observer, {
+    required String? keyPath,
+    required Set<_i7.NSKeyValueObservingOptions>? options,
+  }) =>
+      (super.noSuchMethod(
+        Invocation.method(
+          #addObserver,
+          [observer],
+          {
+            #keyPath: keyPath,
+            #options: options,
+          },
+        ),
+        returnValue: _i5.Future<void>.value(),
+        returnValueForMissingStub: _i5.Future<void>.value(),
+      ) as _i5.Future<void>);
+  @override
+  _i5.Future<void> removeObserver(
+    _i7.NSObject? observer, {
+    required String? keyPath,
+  }) =>
+      (super.noSuchMethod(
+        Invocation.method(
+          #removeObserver,
+          [observer],
+          {#keyPath: keyPath},
+        ),
+        returnValue: _i5.Future<void>.value(),
+        returnValueForMissingStub: _i5.Future<void>.value(),
+      ) as _i5.Future<void>);
+}
+
+/// A class which mocks [WKWebViewConfiguration].
+///
+/// See the documentation for Mockito's code generation for more information.
+// ignore: must_be_immutable
+class MockWKWebViewConfiguration extends _i1.Mock
+    implements _i4.WKWebViewConfiguration {
+  MockWKWebViewConfiguration() {
+    _i1.throwOnMissingStub(this);
+  }
+
+  @override
+  _i4.WKUserContentController get userContentController => (super.noSuchMethod(
+        Invocation.getter(#userContentController),
+        returnValue: _FakeWKUserContentController_7(
+          this,
+          Invocation.getter(#userContentController),
+        ),
+      ) as _i4.WKUserContentController);
+  @override
+  _i4.WKPreferences get preferences => (super.noSuchMethod(
+        Invocation.getter(#preferences),
+        returnValue: _FakeWKPreferences_3(
+          this,
+          Invocation.getter(#preferences),
+        ),
+      ) as _i4.WKPreferences);
+  @override
+  _i4.WKWebsiteDataStore get websiteDataStore => (super.noSuchMethod(
+        Invocation.getter(#websiteDataStore),
+        returnValue: _FakeWKWebsiteDataStore_8(
+          this,
+          Invocation.getter(#websiteDataStore),
+        ),
+      ) as _i4.WKWebsiteDataStore);
+  @override
+  _i5.Future<void> setAllowsInlineMediaPlayback(bool? allow) =>
+      (super.noSuchMethod(
+        Invocation.method(
+          #setAllowsInlineMediaPlayback,
+          [allow],
+        ),
+        returnValue: _i5.Future<void>.value(),
+        returnValueForMissingStub: _i5.Future<void>.value(),
+      ) as _i5.Future<void>);
+  @override
+  _i5.Future<void> setMediaTypesRequiringUserActionForPlayback(
+          Set<_i4.WKAudiovisualMediaType>? types) =>
+      (super.noSuchMethod(
+        Invocation.method(
+          #setMediaTypesRequiringUserActionForPlayback,
+          [types],
+        ),
+        returnValue: _i5.Future<void>.value(),
+        returnValueForMissingStub: _i5.Future<void>.value(),
+      ) as _i5.Future<void>);
+  @override
+  _i4.WKWebViewConfiguration copy() => (super.noSuchMethod(
+        Invocation.method(
+          #copy,
+          [],
+        ),
+        returnValue: _FakeWKWebViewConfiguration_5(
+          this,
+          Invocation.method(
+            #copy,
+            [],
+          ),
+        ),
+      ) as _i4.WKWebViewConfiguration);
+  @override
+  _i5.Future<void> addObserver(
+    _i7.NSObject? observer, {
+    required String? keyPath,
+    required Set<_i7.NSKeyValueObservingOptions>? options,
+  }) =>
+      (super.noSuchMethod(
+        Invocation.method(
+          #addObserver,
+          [observer],
+          {
+            #keyPath: keyPath,
+            #options: options,
+          },
+        ),
+        returnValue: _i5.Future<void>.value(),
+        returnValueForMissingStub: _i5.Future<void>.value(),
+      ) as _i5.Future<void>);
+  @override
+  _i5.Future<void> removeObserver(
+    _i7.NSObject? observer, {
+    required String? keyPath,
+  }) =>
+      (super.noSuchMethod(
+        Invocation.method(
+          #removeObserver,
+          [observer],
+          {#keyPath: keyPath},
+        ),
+        returnValue: _i5.Future<void>.value(),
+        returnValueForMissingStub: _i5.Future<void>.value(),
+      ) as _i5.Future<void>);
+}
+
+/// A class which mocks [WKWebsiteDataStore].
+///
+/// See the documentation for Mockito's code generation for more information.
+// ignore: must_be_immutable
+class MockWKWebsiteDataStore extends _i1.Mock
+    implements _i4.WKWebsiteDataStore {
+  MockWKWebsiteDataStore() {
+    _i1.throwOnMissingStub(this);
+  }
+
+  @override
+  _i4.WKHttpCookieStore get httpCookieStore => (super.noSuchMethod(
+        Invocation.getter(#httpCookieStore),
+        returnValue: _FakeWKHttpCookieStore_9(
+          this,
+          Invocation.getter(#httpCookieStore),
+        ),
+      ) as _i4.WKHttpCookieStore);
+  @override
+  _i5.Future<bool> removeDataOfTypes(
+    Set<_i4.WKWebsiteDataType>? dataTypes,
+    DateTime? since,
+  ) =>
+      (super.noSuchMethod(
+        Invocation.method(
+          #removeDataOfTypes,
+          [
+            dataTypes,
+            since,
+          ],
+        ),
+        returnValue: _i5.Future<bool>.value(false),
+      ) as _i5.Future<bool>);
+  @override
+  _i4.WKWebsiteDataStore copy() => (super.noSuchMethod(
+        Invocation.method(
+          #copy,
+          [],
+        ),
+        returnValue: _FakeWKWebsiteDataStore_8(
+          this,
+          Invocation.method(
+            #copy,
+            [],
+          ),
+        ),
+      ) as _i4.WKWebsiteDataStore);
+  @override
+  _i5.Future<void> addObserver(
+    _i7.NSObject? observer, {
+    required String? keyPath,
+    required Set<_i7.NSKeyValueObservingOptions>? options,
+  }) =>
+      (super.noSuchMethod(
+        Invocation.method(
+          #addObserver,
+          [observer],
+          {
+            #keyPath: keyPath,
+            #options: options,
+          },
+        ),
+        returnValue: _i5.Future<void>.value(),
+        returnValueForMissingStub: _i5.Future<void>.value(),
+      ) as _i5.Future<void>);
+  @override
+  _i5.Future<void> removeObserver(
+    _i7.NSObject? observer, {
+    required String? keyPath,
+  }) =>
+      (super.noSuchMethod(
+        Invocation.method(
+          #removeObserver,
+          [observer],
+          {#keyPath: keyPath},
+        ),
+        returnValue: _i5.Future<void>.value(),
+        returnValueForMissingStub: _i5.Future<void>.value(),
+      ) as _i5.Future<void>);
+}
+
+/// A class which mocks [WKUIDelegate].
+///
+/// See the documentation for Mockito's code generation for more information.
+// ignore: must_be_immutable
+class MockWKUIDelegate extends _i1.Mock implements _i4.WKUIDelegate {
+  MockWKUIDelegate() {
+    _i1.throwOnMissingStub(this);
+  }
+
+  @override
+  _i4.WKUIDelegate copy() => (super.noSuchMethod(
+        Invocation.method(
+          #copy,
+          [],
+        ),
+        returnValue: _FakeWKUIDelegate_10(
+          this,
+          Invocation.method(
+            #copy,
+            [],
+          ),
+        ),
+      ) as _i4.WKUIDelegate);
+  @override
+  _i5.Future<void> addObserver(
+    _i7.NSObject? observer, {
+    required String? keyPath,
+    required Set<_i7.NSKeyValueObservingOptions>? options,
+  }) =>
+      (super.noSuchMethod(
+        Invocation.method(
+          #addObserver,
+          [observer],
+          {
+            #keyPath: keyPath,
+            #options: options,
+          },
+        ),
+        returnValue: _i5.Future<void>.value(),
+        returnValueForMissingStub: _i5.Future<void>.value(),
+      ) as _i5.Future<void>);
+  @override
+  _i5.Future<void> removeObserver(
+    _i7.NSObject? observer, {
+    required String? keyPath,
+  }) =>
+      (super.noSuchMethod(
+        Invocation.method(
+          #removeObserver,
+          [observer],
+          {#keyPath: keyPath},
+        ),
+        returnValue: _i5.Future<void>.value(),
+        returnValueForMissingStub: _i5.Future<void>.value(),
+      ) as _i5.Future<void>);
+}
+
+/// A class which mocks [WKUserContentController].
+///
+/// See the documentation for Mockito's code generation for more information.
+// ignore: must_be_immutable
+class MockWKUserContentController extends _i1.Mock
+    implements _i4.WKUserContentController {
+  MockWKUserContentController() {
+    _i1.throwOnMissingStub(this);
+  }
+
+  @override
+  _i5.Future<void> addScriptMessageHandler(
+    _i4.WKScriptMessageHandler? handler,
+    String? name,
+  ) =>
+      (super.noSuchMethod(
+        Invocation.method(
+          #addScriptMessageHandler,
+          [
+            handler,
+            name,
+          ],
+        ),
+        returnValue: _i5.Future<void>.value(),
+        returnValueForMissingStub: _i5.Future<void>.value(),
+      ) as _i5.Future<void>);
+  @override
+  _i5.Future<void> removeScriptMessageHandler(String? name) =>
+      (super.noSuchMethod(
+        Invocation.method(
+          #removeScriptMessageHandler,
+          [name],
+        ),
+        returnValue: _i5.Future<void>.value(),
+        returnValueForMissingStub: _i5.Future<void>.value(),
+      ) as _i5.Future<void>);
+  @override
+  _i5.Future<void> removeAllScriptMessageHandlers() => (super.noSuchMethod(
+        Invocation.method(
+          #removeAllScriptMessageHandlers,
+          [],
+        ),
+        returnValue: _i5.Future<void>.value(),
+        returnValueForMissingStub: _i5.Future<void>.value(),
+      ) as _i5.Future<void>);
+  @override
+  _i5.Future<void> addUserScript(_i4.WKUserScript? userScript) =>
+      (super.noSuchMethod(
+        Invocation.method(
+          #addUserScript,
+          [userScript],
+        ),
+        returnValue: _i5.Future<void>.value(),
+        returnValueForMissingStub: _i5.Future<void>.value(),
+      ) as _i5.Future<void>);
+  @override
+  _i5.Future<void> removeAllUserScripts() => (super.noSuchMethod(
+        Invocation.method(
+          #removeAllUserScripts,
+          [],
+        ),
+        returnValue: _i5.Future<void>.value(),
+        returnValueForMissingStub: _i5.Future<void>.value(),
+      ) as _i5.Future<void>);
+  @override
+  _i4.WKUserContentController copy() => (super.noSuchMethod(
+        Invocation.method(
+          #copy,
+          [],
+        ),
+        returnValue: _FakeWKUserContentController_7(
+          this,
+          Invocation.method(
+            #copy,
+            [],
+          ),
+        ),
+      ) as _i4.WKUserContentController);
+  @override
+  _i5.Future<void> addObserver(
+    _i7.NSObject? observer, {
+    required String? keyPath,
+    required Set<_i7.NSKeyValueObservingOptions>? options,
+  }) =>
+      (super.noSuchMethod(
+        Invocation.method(
+          #addObserver,
+          [observer],
+          {
+            #keyPath: keyPath,
+            #options: options,
+          },
+        ),
+        returnValue: _i5.Future<void>.value(),
+        returnValueForMissingStub: _i5.Future<void>.value(),
+      ) as _i5.Future<void>);
+  @override
+  _i5.Future<void> removeObserver(
+    _i7.NSObject? observer, {
+    required String? keyPath,
+  }) =>
+      (super.noSuchMethod(
+        Invocation.method(
+          #removeObserver,
+          [observer],
+          {#keyPath: keyPath},
+        ),
+        returnValue: _i5.Future<void>.value(),
+        returnValueForMissingStub: _i5.Future<void>.value(),
+      ) as _i5.Future<void>);
+}
+
+/// A class which mocks [JavascriptChannelRegistry].
+///
+/// See the documentation for Mockito's code generation for more information.
+class MockJavascriptChannelRegistry extends _i1.Mock
+    implements _i8.JavascriptChannelRegistry {
+  MockJavascriptChannelRegistry() {
+    _i1.throwOnMissingStub(this);
+  }
+
+  @override
+  Map<String, _i9.JavascriptChannel> get channels => (super.noSuchMethod(
+        Invocation.getter(#channels),
+        returnValue: <String, _i9.JavascriptChannel>{},
+      ) as Map<String, _i9.JavascriptChannel>);
+  @override
+  void onJavascriptChannelMessage(
+    String? channel,
+    String? message,
+  ) =>
+      super.noSuchMethod(
+        Invocation.method(
+          #onJavascriptChannelMessage,
+          [
+            channel,
+            message,
+          ],
+        ),
+        returnValueForMissingStub: null,
+      );
+  @override
+  void updateJavascriptChannelsFromSet(Set<_i9.JavascriptChannel>? channels) =>
+      super.noSuchMethod(
+        Invocation.method(
+          #updateJavascriptChannelsFromSet,
+          [channels],
+        ),
+        returnValueForMissingStub: null,
+      );
+}
+
+/// A class which mocks [WebViewPlatformCallbacksHandler].
+///
+/// See the documentation for Mockito's code generation for more information.
+class MockWebViewPlatformCallbacksHandler extends _i1.Mock
+    implements _i8.WebViewPlatformCallbacksHandler {
+  MockWebViewPlatformCallbacksHandler() {
+    _i1.throwOnMissingStub(this);
+  }
+
+  @override
+  _i5.FutureOr<bool> onNavigationRequest({
+    required String? url,
+    required bool? isForMainFrame,
+  }) =>
+      (super.noSuchMethod(
+        Invocation.method(
+          #onNavigationRequest,
+          [],
+          {
+            #url: url,
+            #isForMainFrame: isForMainFrame,
+          },
+        ),
+        returnValue: _i5.Future<bool>.value(false),
+      ) as _i5.FutureOr<bool>);
+  @override
+  void onPageStarted(String? url) => super.noSuchMethod(
+        Invocation.method(
+          #onPageStarted,
+          [url],
+        ),
+        returnValueForMissingStub: null,
+      );
+  @override
+  void onPageFinished(String? url) => super.noSuchMethod(
+        Invocation.method(
+          #onPageFinished,
+          [url],
+        ),
+        returnValueForMissingStub: null,
+      );
+  @override
+  void onProgress(int? progress) => super.noSuchMethod(
+        Invocation.method(
+          #onProgress,
+          [progress],
+        ),
+        returnValueForMissingStub: null,
+      );
+  @override
+  void onWebResourceError(_i10.WebResourceError? error) => super.noSuchMethod(
+        Invocation.method(
+          #onWebResourceError,
+          [error],
+        ),
+        returnValueForMissingStub: null,
+      );
+}
+
+/// A class which mocks [WebViewWidgetProxy].
+///
+/// See the documentation for Mockito's code generation for more information.
+class MockWebViewWidgetProxy extends _i1.Mock
+    implements _i11.WebViewWidgetProxy {
+  MockWebViewWidgetProxy() {
+    _i1.throwOnMissingStub(this);
+  }
+
+  @override
+  _i4.WKWebView createWebView(
+    _i4.WKWebViewConfiguration? configuration, {
+    void Function(
+      String,
+      _i7.NSObject,
+      Map<_i7.NSKeyValueChangeKey, Object?>,
+    )?
+        observeValue,
+  }) =>
+      (super.noSuchMethod(
+        Invocation.method(
+          #createWebView,
+          [configuration],
+          {#observeValue: observeValue},
+        ),
+        returnValue: _FakeWKWebView_6(
+          this,
+          Invocation.method(
+            #createWebView,
+            [configuration],
+            {#observeValue: observeValue},
+          ),
+        ),
+      ) as _i4.WKWebView);
+  @override
+  _i4.WKScriptMessageHandler createScriptMessageHandler(
+          {required void Function(
+            _i4.WKUserContentController,
+            _i4.WKScriptMessage,
+          )?
+              didReceiveScriptMessage}) =>
+      (super.noSuchMethod(
+        Invocation.method(
+          #createScriptMessageHandler,
+          [],
+          {#didReceiveScriptMessage: didReceiveScriptMessage},
+        ),
+        returnValue: _FakeWKScriptMessageHandler_4(
+          this,
+          Invocation.method(
+            #createScriptMessageHandler,
+            [],
+            {#didReceiveScriptMessage: didReceiveScriptMessage},
+          ),
+        ),
+      ) as _i4.WKScriptMessageHandler);
+  @override
+  _i4.WKUIDelegate createUIDelgate(
+          {void Function(
+            _i4.WKWebView,
+            _i4.WKWebViewConfiguration,
+            _i4.WKNavigationAction,
+          )?
+              onCreateWebView}) =>
+      (super.noSuchMethod(
+        Invocation.method(
+          #createUIDelgate,
+          [],
+          {#onCreateWebView: onCreateWebView},
+        ),
+        returnValue: _FakeWKUIDelegate_10(
+          this,
+          Invocation.method(
+            #createUIDelgate,
+            [],
+            {#onCreateWebView: onCreateWebView},
+          ),
+        ),
+      ) as _i4.WKUIDelegate);
+  @override
+  _i4.WKNavigationDelegate createNavigationDelegate({
+    void Function(
+      _i4.WKWebView,
+      String?,
+    )?
+        didFinishNavigation,
+    void Function(
+      _i4.WKWebView,
+      String?,
+    )?
+        didStartProvisionalNavigation,
+    _i5.Future<_i4.WKNavigationActionPolicy> Function(
+      _i4.WKWebView,
+      _i4.WKNavigationAction,
+    )?
+        decidePolicyForNavigationAction,
+    void Function(
+      _i4.WKWebView,
+      _i7.NSError,
+    )?
+        didFailNavigation,
+    void Function(
+      _i4.WKWebView,
+      _i7.NSError,
+    )?
+        didFailProvisionalNavigation,
+    void Function(_i4.WKWebView)? webViewWebContentProcessDidTerminate,
+  }) =>
+      (super.noSuchMethod(
+        Invocation.method(
+          #createNavigationDelegate,
+          [],
+          {
+            #didFinishNavigation: didFinishNavigation,
+            #didStartProvisionalNavigation: didStartProvisionalNavigation,
+            #decidePolicyForNavigationAction: decidePolicyForNavigationAction,
+            #didFailNavigation: didFailNavigation,
+            #didFailProvisionalNavigation: didFailProvisionalNavigation,
+            #webViewWebContentProcessDidTerminate:
+                webViewWebContentProcessDidTerminate,
+          },
+        ),
+        returnValue: _FakeWKNavigationDelegate_2(
+          this,
+          Invocation.method(
+            #createNavigationDelegate,
+            [],
+            {
+              #didFinishNavigation: didFinishNavigation,
+              #didStartProvisionalNavigation: didStartProvisionalNavigation,
+              #decidePolicyForNavigationAction: decidePolicyForNavigationAction,
+              #didFailNavigation: didFailNavigation,
+              #didFailProvisionalNavigation: didFailProvisionalNavigation,
+              #webViewWebContentProcessDidTerminate:
+                  webViewWebContentProcessDidTerminate,
+            },
+          ),
+        ),
+      ) as _i4.WKNavigationDelegate);
+}
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/test/src/foundation/foundation_test.mocks.dart b/packages/webview_flutter/webview_flutter_wkwebview/test/src/foundation/foundation_test.mocks.dart
index 62a51e1..fe80a54 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/test/src/foundation/foundation_test.mocks.dart
+++ b/packages/webview_flutter/webview_flutter_wkwebview/test/src/foundation/foundation_test.mocks.dart
@@ -1,7 +1,8 @@
-// Mocks generated by Mockito 5.2.0 from annotations
-// in webview_flutter_wkwebview/example/ios/.symlinks/plugins/webview_flutter_wkwebview/test/src/foundation/foundation_test.dart.
+// Mocks generated by Mockito 5.3.2 from annotations
+// in webview_flutter_wkwebview/test/src/foundation/foundation_test.dart.
 // Do not manually edit this file.
 
+// ignore_for_file: no_leading_underscores_for_library_prefixes
 import 'package:mockito/mockito.dart' as _i1;
 import 'package:webview_flutter_wkwebview/src/common/web_kit.pigeon.dart'
     as _i3;
@@ -17,6 +18,7 @@
 // ignore_for_file: prefer_const_constructors
 // ignore_for_file: unnecessary_parenthesis
 // ignore_for_file: camel_case_types
+// ignore_for_file: subtype_of_sealed_class
 
 /// A class which mocks [TestNSObjectHostApi].
 ///
@@ -28,21 +30,47 @@
   }
 
   @override
-  void dispose(int? identifier) =>
-      super.noSuchMethod(Invocation.method(#dispose, [identifier]),
-          returnValueForMissingStub: null);
+  void dispose(int? identifier) => super.noSuchMethod(
+        Invocation.method(
+          #dispose,
+          [identifier],
+        ),
+        returnValueForMissingStub: null,
+      );
   @override
-  void addObserver(int? identifier, int? observerIdentifier, String? keyPath,
-          List<_i3.NSKeyValueObservingOptionsEnumData?>? options) =>
+  void addObserver(
+    int? identifier,
+    int? observerIdentifier,
+    String? keyPath,
+    List<_i3.NSKeyValueObservingOptionsEnumData?>? options,
+  ) =>
       super.noSuchMethod(
-          Invocation.method(
-              #addObserver, [identifier, observerIdentifier, keyPath, options]),
-          returnValueForMissingStub: null);
+        Invocation.method(
+          #addObserver,
+          [
+            identifier,
+            observerIdentifier,
+            keyPath,
+            options,
+          ],
+        ),
+        returnValueForMissingStub: null,
+      );
   @override
   void removeObserver(
-          int? identifier, int? observerIdentifier, String? keyPath) =>
+    int? identifier,
+    int? observerIdentifier,
+    String? keyPath,
+  ) =>
       super.noSuchMethod(
-          Invocation.method(
-              #removeObserver, [identifier, observerIdentifier, keyPath]),
-          returnValueForMissingStub: null);
+        Invocation.method(
+          #removeObserver,
+          [
+            identifier,
+            observerIdentifier,
+            keyPath,
+          ],
+        ),
+        returnValueForMissingStub: null,
+      );
 }
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/test/src/ui_kit/ui_kit_test.mocks.dart b/packages/webview_flutter/webview_flutter_wkwebview/test/src/ui_kit/ui_kit_test.mocks.dart
index a382ecf..660c448 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/test/src/ui_kit/ui_kit_test.mocks.dart
+++ b/packages/webview_flutter/webview_flutter_wkwebview/test/src/ui_kit/ui_kit_test.mocks.dart
@@ -1,7 +1,8 @@
-// Mocks generated by Mockito 5.2.0 from annotations
-// in webview_flutter_wkwebview/example/ios/.symlinks/plugins/webview_flutter_wkwebview/test/src/ui_kit/ui_kit_test.dart.
+// Mocks generated by Mockito 5.3.2 from annotations
+// in webview_flutter_wkwebview/test/src/ui_kit/ui_kit_test.dart.
 // Do not manually edit this file.
 
+// ignore_for_file: no_leading_underscores_for_library_prefixes
 import 'dart:async' as _i4;
 
 import 'package:mockito/mockito.dart' as _i1;
@@ -19,6 +20,7 @@
 // ignore_for_file: prefer_const_constructors
 // ignore_for_file: unnecessary_parenthesis
 // ignore_for_file: camel_case_types
+// ignore_for_file: subtype_of_sealed_class
 
 /// A class which mocks [TestWKWebViewConfigurationHostApi].
 ///
@@ -30,27 +32,58 @@
   }
 
   @override
-  void create(int? identifier) =>
-      super.noSuchMethod(Invocation.method(#create, [identifier]),
-          returnValueForMissingStub: null);
+  void create(int? identifier) => super.noSuchMethod(
+        Invocation.method(
+          #create,
+          [identifier],
+        ),
+        returnValueForMissingStub: null,
+      );
   @override
-  void createFromWebView(int? identifier, int? webViewIdentifier) =>
+  void createFromWebView(
+    int? identifier,
+    int? webViewIdentifier,
+  ) =>
       super.noSuchMethod(
-          Invocation.method(
-              #createFromWebView, [identifier, webViewIdentifier]),
-          returnValueForMissingStub: null);
+        Invocation.method(
+          #createFromWebView,
+          [
+            identifier,
+            webViewIdentifier,
+          ],
+        ),
+        returnValueForMissingStub: null,
+      );
   @override
-  void setAllowsInlineMediaPlayback(int? identifier, bool? allow) =>
+  void setAllowsInlineMediaPlayback(
+    int? identifier,
+    bool? allow,
+  ) =>
       super.noSuchMethod(
-          Invocation.method(#setAllowsInlineMediaPlayback, [identifier, allow]),
-          returnValueForMissingStub: null);
+        Invocation.method(
+          #setAllowsInlineMediaPlayback,
+          [
+            identifier,
+            allow,
+          ],
+        ),
+        returnValueForMissingStub: null,
+      );
   @override
   void setMediaTypesRequiringUserActionForPlayback(
-          int? identifier, List<_i3.WKAudiovisualMediaTypeEnumData?>? types) =>
+    int? identifier,
+    List<_i3.WKAudiovisualMediaTypeEnumData?>? types,
+  ) =>
       super.noSuchMethod(
-          Invocation.method(#setMediaTypesRequiringUserActionForPlayback,
-              [identifier, types]),
-          returnValueForMissingStub: null);
+        Invocation.method(
+          #setMediaTypesRequiringUserActionForPlayback,
+          [
+            identifier,
+            types,
+          ],
+        ),
+        returnValueForMissingStub: null,
+      );
 }
 
 /// A class which mocks [TestWKWebViewHostApi].
@@ -63,89 +96,217 @@
   }
 
   @override
-  void create(int? identifier, int? configurationIdentifier) =>
+  void create(
+    int? identifier,
+    int? configurationIdentifier,
+  ) =>
       super.noSuchMethod(
-          Invocation.method(#create, [identifier, configurationIdentifier]),
-          returnValueForMissingStub: null);
+        Invocation.method(
+          #create,
+          [
+            identifier,
+            configurationIdentifier,
+          ],
+        ),
+        returnValueForMissingStub: null,
+      );
   @override
-  void setUIDelegate(int? identifier, int? uiDelegateIdentifier) =>
+  void setUIDelegate(
+    int? identifier,
+    int? uiDelegateIdentifier,
+  ) =>
       super.noSuchMethod(
-          Invocation.method(#setUIDelegate, [identifier, uiDelegateIdentifier]),
-          returnValueForMissingStub: null);
+        Invocation.method(
+          #setUIDelegate,
+          [
+            identifier,
+            uiDelegateIdentifier,
+          ],
+        ),
+        returnValueForMissingStub: null,
+      );
   @override
   void setNavigationDelegate(
-          int? identifier, int? navigationDelegateIdentifier) =>
+    int? identifier,
+    int? navigationDelegateIdentifier,
+  ) =>
       super.noSuchMethod(
-          Invocation.method(#setNavigationDelegate,
-              [identifier, navigationDelegateIdentifier]),
-          returnValueForMissingStub: null);
+        Invocation.method(
+          #setNavigationDelegate,
+          [
+            identifier,
+            navigationDelegateIdentifier,
+          ],
+        ),
+        returnValueForMissingStub: null,
+      );
   @override
-  String? getUrl(int? identifier) =>
-      (super.noSuchMethod(Invocation.method(#getUrl, [identifier])) as String?);
+  String? getUrl(int? identifier) => (super.noSuchMethod(Invocation.method(
+        #getUrl,
+        [identifier],
+      )) as String?);
   @override
   double getEstimatedProgress(int? identifier) => (super.noSuchMethod(
-      Invocation.method(#getEstimatedProgress, [identifier]),
-      returnValue: 0.0) as double);
+        Invocation.method(
+          #getEstimatedProgress,
+          [identifier],
+        ),
+        returnValue: 0.0,
+      ) as double);
   @override
-  void loadRequest(int? identifier, _i3.NSUrlRequestData? request) =>
-      super.noSuchMethod(Invocation.method(#loadRequest, [identifier, request]),
-          returnValueForMissingStub: null);
-  @override
-  void loadHtmlString(int? identifier, String? string, String? baseUrl) =>
+  void loadRequest(
+    int? identifier,
+    _i3.NSUrlRequestData? request,
+  ) =>
       super.noSuchMethod(
-          Invocation.method(#loadHtmlString, [identifier, string, baseUrl]),
-          returnValueForMissingStub: null);
+        Invocation.method(
+          #loadRequest,
+          [
+            identifier,
+            request,
+          ],
+        ),
+        returnValueForMissingStub: null,
+      );
   @override
-  void loadFileUrl(int? identifier, String? url, String? readAccessUrl) =>
+  void loadHtmlString(
+    int? identifier,
+    String? string,
+    String? baseUrl,
+  ) =>
       super.noSuchMethod(
-          Invocation.method(#loadFileUrl, [identifier, url, readAccessUrl]),
-          returnValueForMissingStub: null);
+        Invocation.method(
+          #loadHtmlString,
+          [
+            identifier,
+            string,
+            baseUrl,
+          ],
+        ),
+        returnValueForMissingStub: null,
+      );
   @override
-  void loadFlutterAsset(int? identifier, String? key) => super.noSuchMethod(
-      Invocation.method(#loadFlutterAsset, [identifier, key]),
-      returnValueForMissingStub: null);
-  @override
-  bool canGoBack(int? identifier) =>
-      (super.noSuchMethod(Invocation.method(#canGoBack, [identifier]),
-          returnValue: false) as bool);
-  @override
-  bool canGoForward(int? identifier) =>
-      (super.noSuchMethod(Invocation.method(#canGoForward, [identifier]),
-          returnValue: false) as bool);
-  @override
-  void goBack(int? identifier) =>
-      super.noSuchMethod(Invocation.method(#goBack, [identifier]),
-          returnValueForMissingStub: null);
-  @override
-  void goForward(int? identifier) =>
-      super.noSuchMethod(Invocation.method(#goForward, [identifier]),
-          returnValueForMissingStub: null);
-  @override
-  void reload(int? identifier) =>
-      super.noSuchMethod(Invocation.method(#reload, [identifier]),
-          returnValueForMissingStub: null);
-  @override
-  String? getTitle(int? identifier) =>
-      (super.noSuchMethod(Invocation.method(#getTitle, [identifier]))
-          as String?);
-  @override
-  void setAllowsBackForwardNavigationGestures(int? identifier, bool? allow) =>
+  void loadFileUrl(
+    int? identifier,
+    String? url,
+    String? readAccessUrl,
+  ) =>
       super.noSuchMethod(
-          Invocation.method(
-              #setAllowsBackForwardNavigationGestures, [identifier, allow]),
-          returnValueForMissingStub: null);
+        Invocation.method(
+          #loadFileUrl,
+          [
+            identifier,
+            url,
+            readAccessUrl,
+          ],
+        ),
+        returnValueForMissingStub: null,
+      );
   @override
-  void setCustomUserAgent(int? identifier, String? userAgent) =>
+  void loadFlutterAsset(
+    int? identifier,
+    String? key,
+  ) =>
       super.noSuchMethod(
-          Invocation.method(#setCustomUserAgent, [identifier, userAgent]),
-          returnValueForMissingStub: null);
+        Invocation.method(
+          #loadFlutterAsset,
+          [
+            identifier,
+            key,
+          ],
+        ),
+        returnValueForMissingStub: null,
+      );
+  @override
+  bool canGoBack(int? identifier) => (super.noSuchMethod(
+        Invocation.method(
+          #canGoBack,
+          [identifier],
+        ),
+        returnValue: false,
+      ) as bool);
+  @override
+  bool canGoForward(int? identifier) => (super.noSuchMethod(
+        Invocation.method(
+          #canGoForward,
+          [identifier],
+        ),
+        returnValue: false,
+      ) as bool);
+  @override
+  void goBack(int? identifier) => super.noSuchMethod(
+        Invocation.method(
+          #goBack,
+          [identifier],
+        ),
+        returnValueForMissingStub: null,
+      );
+  @override
+  void goForward(int? identifier) => super.noSuchMethod(
+        Invocation.method(
+          #goForward,
+          [identifier],
+        ),
+        returnValueForMissingStub: null,
+      );
+  @override
+  void reload(int? identifier) => super.noSuchMethod(
+        Invocation.method(
+          #reload,
+          [identifier],
+        ),
+        returnValueForMissingStub: null,
+      );
+  @override
+  String? getTitle(int? identifier) => (super.noSuchMethod(Invocation.method(
+        #getTitle,
+        [identifier],
+      )) as String?);
+  @override
+  void setAllowsBackForwardNavigationGestures(
+    int? identifier,
+    bool? allow,
+  ) =>
+      super.noSuchMethod(
+        Invocation.method(
+          #setAllowsBackForwardNavigationGestures,
+          [
+            identifier,
+            allow,
+          ],
+        ),
+        returnValueForMissingStub: null,
+      );
+  @override
+  void setCustomUserAgent(
+    int? identifier,
+    String? userAgent,
+  ) =>
+      super.noSuchMethod(
+        Invocation.method(
+          #setCustomUserAgent,
+          [
+            identifier,
+            userAgent,
+          ],
+        ),
+        returnValueForMissingStub: null,
+      );
   @override
   _i4.Future<Object?> evaluateJavaScript(
-          int? identifier, String? javaScriptString) =>
+    int? identifier,
+    String? javaScriptString,
+  ) =>
       (super.noSuchMethod(
-          Invocation.method(
-              #evaluateJavaScript, [identifier, javaScriptString]),
-          returnValue: Future<Object?>.value()) as _i4.Future<Object?>);
+        Invocation.method(
+          #evaluateJavaScript,
+          [
+            identifier,
+            javaScriptString,
+          ],
+        ),
+        returnValue: _i4.Future<Object?>.value(),
+      ) as _i4.Future<Object?>);
 }
 
 /// A class which mocks [TestUIScrollViewHostApi].
@@ -158,23 +319,62 @@
   }
 
   @override
-  void createFromWebView(int? identifier, int? webViewIdentifier) =>
+  void createFromWebView(
+    int? identifier,
+    int? webViewIdentifier,
+  ) =>
       super.noSuchMethod(
-          Invocation.method(
-              #createFromWebView, [identifier, webViewIdentifier]),
-          returnValueForMissingStub: null);
+        Invocation.method(
+          #createFromWebView,
+          [
+            identifier,
+            webViewIdentifier,
+          ],
+        ),
+        returnValueForMissingStub: null,
+      );
   @override
-  List<double?> getContentOffset(int? identifier) =>
-      (super.noSuchMethod(Invocation.method(#getContentOffset, [identifier]),
-          returnValue: <double?>[]) as List<double?>);
+  List<double?> getContentOffset(int? identifier) => (super.noSuchMethod(
+        Invocation.method(
+          #getContentOffset,
+          [identifier],
+        ),
+        returnValue: <double?>[],
+      ) as List<double?>);
   @override
-  void scrollBy(int? identifier, double? x, double? y) =>
-      super.noSuchMethod(Invocation.method(#scrollBy, [identifier, x, y]),
-          returnValueForMissingStub: null);
+  void scrollBy(
+    int? identifier,
+    double? x,
+    double? y,
+  ) =>
+      super.noSuchMethod(
+        Invocation.method(
+          #scrollBy,
+          [
+            identifier,
+            x,
+            y,
+          ],
+        ),
+        returnValueForMissingStub: null,
+      );
   @override
-  void setContentOffset(int? identifier, double? x, double? y) => super
-      .noSuchMethod(Invocation.method(#setContentOffset, [identifier, x, y]),
-          returnValueForMissingStub: null);
+  void setContentOffset(
+    int? identifier,
+    double? x,
+    double? y,
+  ) =>
+      super.noSuchMethod(
+        Invocation.method(
+          #setContentOffset,
+          [
+            identifier,
+            x,
+            y,
+          ],
+        ),
+        returnValueForMissingStub: null,
+      );
 }
 
 /// A class which mocks [TestUIViewHostApi].
@@ -186,11 +386,33 @@
   }
 
   @override
-  void setBackgroundColor(int? identifier, int? value) => super.noSuchMethod(
-      Invocation.method(#setBackgroundColor, [identifier, value]),
-      returnValueForMissingStub: null);
+  void setBackgroundColor(
+    int? identifier,
+    int? value,
+  ) =>
+      super.noSuchMethod(
+        Invocation.method(
+          #setBackgroundColor,
+          [
+            identifier,
+            value,
+          ],
+        ),
+        returnValueForMissingStub: null,
+      );
   @override
-  void setOpaque(int? identifier, bool? opaque) =>
-      super.noSuchMethod(Invocation.method(#setOpaque, [identifier, opaque]),
-          returnValueForMissingStub: null);
+  void setOpaque(
+    int? identifier,
+    bool? opaque,
+  ) =>
+      super.noSuchMethod(
+        Invocation.method(
+          #setOpaque,
+          [
+            identifier,
+            opaque,
+          ],
+        ),
+        returnValueForMissingStub: null,
+      );
 }
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/test/src/web_kit/web_kit_test.mocks.dart b/packages/webview_flutter/webview_flutter_wkwebview/test/src/web_kit/web_kit_test.mocks.dart
index 18f30d4..a1a5bf2 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/test/src/web_kit/web_kit_test.mocks.dart
+++ b/packages/webview_flutter/webview_flutter_wkwebview/test/src/web_kit/web_kit_test.mocks.dart
@@ -1,7 +1,8 @@
-// Mocks generated by Mockito 5.2.0 from annotations
-// in webview_flutter_wkwebview/example/ios/.symlinks/plugins/webview_flutter_wkwebview/test/src/web_kit/web_kit_test.dart.
+// Mocks generated by Mockito 5.3.2 from annotations
+// in webview_flutter_wkwebview/test/src/web_kit/web_kit_test.dart.
 // Do not manually edit this file.
 
+// ignore_for_file: no_leading_underscores_for_library_prefixes
 import 'dart:async' as _i3;
 
 import 'package:mockito/mockito.dart' as _i1;
@@ -19,6 +20,7 @@
 // ignore_for_file: prefer_const_constructors
 // ignore_for_file: unnecessary_parenthesis
 // ignore_for_file: camel_case_types
+// ignore_for_file: subtype_of_sealed_class
 
 /// A class which mocks [TestWKHttpCookieStoreHostApi].
 ///
@@ -31,16 +33,35 @@
 
   @override
   void createFromWebsiteDataStore(
-          int? identifier, int? websiteDataStoreIdentifier) =>
+    int? identifier,
+    int? websiteDataStoreIdentifier,
+  ) =>
       super.noSuchMethod(
-          Invocation.method(#createFromWebsiteDataStore,
-              [identifier, websiteDataStoreIdentifier]),
-          returnValueForMissingStub: null);
+        Invocation.method(
+          #createFromWebsiteDataStore,
+          [
+            identifier,
+            websiteDataStoreIdentifier,
+          ],
+        ),
+        returnValueForMissingStub: null,
+      );
   @override
-  _i3.Future<void> setCookie(int? identifier, _i4.NSHttpCookieData? cookie) =>
-      (super.noSuchMethod(Invocation.method(#setCookie, [identifier, cookie]),
-          returnValue: Future<void>.value(),
-          returnValueForMissingStub: Future<void>.value()) as _i3.Future<void>);
+  _i3.Future<void> setCookie(
+    int? identifier,
+    _i4.NSHttpCookieData? cookie,
+  ) =>
+      (super.noSuchMethod(
+        Invocation.method(
+          #setCookie,
+          [
+            identifier,
+            cookie,
+          ],
+        ),
+        returnValue: _i3.Future<void>.value(),
+        returnValueForMissingStub: _i3.Future<void>.value(),
+      ) as _i3.Future<void>);
 }
 
 /// A class which mocks [TestWKNavigationDelegateHostApi].
@@ -53,9 +74,13 @@
   }
 
   @override
-  void create(int? identifier) =>
-      super.noSuchMethod(Invocation.method(#create, [identifier]),
-          returnValueForMissingStub: null);
+  void create(int? identifier) => super.noSuchMethod(
+        Invocation.method(
+          #create,
+          [identifier],
+        ),
+        returnValueForMissingStub: null,
+      );
 }
 
 /// A class which mocks [TestWKPreferencesHostApi].
@@ -69,16 +94,34 @@
 
   @override
   void createFromWebViewConfiguration(
-          int? identifier, int? configurationIdentifier) =>
+    int? identifier,
+    int? configurationIdentifier,
+  ) =>
       super.noSuchMethod(
-          Invocation.method(#createFromWebViewConfiguration,
-              [identifier, configurationIdentifier]),
-          returnValueForMissingStub: null);
+        Invocation.method(
+          #createFromWebViewConfiguration,
+          [
+            identifier,
+            configurationIdentifier,
+          ],
+        ),
+        returnValueForMissingStub: null,
+      );
   @override
-  void setJavaScriptEnabled(int? identifier, bool? enabled) =>
+  void setJavaScriptEnabled(
+    int? identifier,
+    bool? enabled,
+  ) =>
       super.noSuchMethod(
-          Invocation.method(#setJavaScriptEnabled, [identifier, enabled]),
-          returnValueForMissingStub: null);
+        Invocation.method(
+          #setJavaScriptEnabled,
+          [
+            identifier,
+            enabled,
+          ],
+        ),
+        returnValueForMissingStub: null,
+      );
 }
 
 /// A class which mocks [TestWKScriptMessageHandlerHostApi].
@@ -91,9 +134,13 @@
   }
 
   @override
-  void create(int? identifier) =>
-      super.noSuchMethod(Invocation.method(#create, [identifier]),
-          returnValueForMissingStub: null);
+  void create(int? identifier) => super.noSuchMethod(
+        Invocation.method(
+          #create,
+          [identifier],
+        ),
+        returnValueForMissingStub: null,
+      );
 }
 
 /// A class which mocks [TestWKUIDelegateHostApi].
@@ -106,9 +153,13 @@
   }
 
   @override
-  void create(int? identifier) =>
-      super.noSuchMethod(Invocation.method(#create, [identifier]),
-          returnValueForMissingStub: null);
+  void create(int? identifier) => super.noSuchMethod(
+        Invocation.method(
+          #create,
+          [identifier],
+        ),
+        returnValueForMissingStub: null,
+      );
 }
 
 /// A class which mocks [TestWKUserContentControllerHostApi].
@@ -122,35 +173,82 @@
 
   @override
   void createFromWebViewConfiguration(
-          int? identifier, int? configurationIdentifier) =>
+    int? identifier,
+    int? configurationIdentifier,
+  ) =>
       super.noSuchMethod(
-          Invocation.method(#createFromWebViewConfiguration,
-              [identifier, configurationIdentifier]),
-          returnValueForMissingStub: null);
+        Invocation.method(
+          #createFromWebViewConfiguration,
+          [
+            identifier,
+            configurationIdentifier,
+          ],
+        ),
+        returnValueForMissingStub: null,
+      );
   @override
   void addScriptMessageHandler(
-          int? identifier, int? handlerIdentifier, String? name) =>
+    int? identifier,
+    int? handlerIdentifier,
+    String? name,
+  ) =>
       super.noSuchMethod(
-          Invocation.method(
-              #addScriptMessageHandler, [identifier, handlerIdentifier, name]),
-          returnValueForMissingStub: null);
+        Invocation.method(
+          #addScriptMessageHandler,
+          [
+            identifier,
+            handlerIdentifier,
+            name,
+          ],
+        ),
+        returnValueForMissingStub: null,
+      );
   @override
-  void removeScriptMessageHandler(int? identifier, String? name) =>
+  void removeScriptMessageHandler(
+    int? identifier,
+    String? name,
+  ) =>
       super.noSuchMethod(
-          Invocation.method(#removeScriptMessageHandler, [identifier, name]),
-          returnValueForMissingStub: null);
+        Invocation.method(
+          #removeScriptMessageHandler,
+          [
+            identifier,
+            name,
+          ],
+        ),
+        returnValueForMissingStub: null,
+      );
   @override
   void removeAllScriptMessageHandlers(int? identifier) => super.noSuchMethod(
-      Invocation.method(#removeAllScriptMessageHandlers, [identifier]),
-      returnValueForMissingStub: null);
+        Invocation.method(
+          #removeAllScriptMessageHandlers,
+          [identifier],
+        ),
+        returnValueForMissingStub: null,
+      );
   @override
-  void addUserScript(int? identifier, _i4.WKUserScriptData? userScript) => super
-      .noSuchMethod(Invocation.method(#addUserScript, [identifier, userScript]),
-          returnValueForMissingStub: null);
+  void addUserScript(
+    int? identifier,
+    _i4.WKUserScriptData? userScript,
+  ) =>
+      super.noSuchMethod(
+        Invocation.method(
+          #addUserScript,
+          [
+            identifier,
+            userScript,
+          ],
+        ),
+        returnValueForMissingStub: null,
+      );
   @override
-  void removeAllUserScripts(int? identifier) =>
-      super.noSuchMethod(Invocation.method(#removeAllUserScripts, [identifier]),
-          returnValueForMissingStub: null);
+  void removeAllUserScripts(int? identifier) => super.noSuchMethod(
+        Invocation.method(
+          #removeAllUserScripts,
+          [identifier],
+        ),
+        returnValueForMissingStub: null,
+      );
 }
 
 /// A class which mocks [TestWKWebViewConfigurationHostApi].
@@ -163,27 +261,58 @@
   }
 
   @override
-  void create(int? identifier) =>
-      super.noSuchMethod(Invocation.method(#create, [identifier]),
-          returnValueForMissingStub: null);
+  void create(int? identifier) => super.noSuchMethod(
+        Invocation.method(
+          #create,
+          [identifier],
+        ),
+        returnValueForMissingStub: null,
+      );
   @override
-  void createFromWebView(int? identifier, int? webViewIdentifier) =>
+  void createFromWebView(
+    int? identifier,
+    int? webViewIdentifier,
+  ) =>
       super.noSuchMethod(
-          Invocation.method(
-              #createFromWebView, [identifier, webViewIdentifier]),
-          returnValueForMissingStub: null);
+        Invocation.method(
+          #createFromWebView,
+          [
+            identifier,
+            webViewIdentifier,
+          ],
+        ),
+        returnValueForMissingStub: null,
+      );
   @override
-  void setAllowsInlineMediaPlayback(int? identifier, bool? allow) =>
+  void setAllowsInlineMediaPlayback(
+    int? identifier,
+    bool? allow,
+  ) =>
       super.noSuchMethod(
-          Invocation.method(#setAllowsInlineMediaPlayback, [identifier, allow]),
-          returnValueForMissingStub: null);
+        Invocation.method(
+          #setAllowsInlineMediaPlayback,
+          [
+            identifier,
+            allow,
+          ],
+        ),
+        returnValueForMissingStub: null,
+      );
   @override
   void setMediaTypesRequiringUserActionForPlayback(
-          int? identifier, List<_i4.WKAudiovisualMediaTypeEnumData?>? types) =>
+    int? identifier,
+    List<_i4.WKAudiovisualMediaTypeEnumData?>? types,
+  ) =>
       super.noSuchMethod(
-          Invocation.method(#setMediaTypesRequiringUserActionForPlayback,
-              [identifier, types]),
-          returnValueForMissingStub: null);
+        Invocation.method(
+          #setMediaTypesRequiringUserActionForPlayback,
+          [
+            identifier,
+            types,
+          ],
+        ),
+        returnValueForMissingStub: null,
+      );
 }
 
 /// A class which mocks [TestWKWebViewHostApi].
@@ -196,89 +325,217 @@
   }
 
   @override
-  void create(int? identifier, int? configurationIdentifier) =>
+  void create(
+    int? identifier,
+    int? configurationIdentifier,
+  ) =>
       super.noSuchMethod(
-          Invocation.method(#create, [identifier, configurationIdentifier]),
-          returnValueForMissingStub: null);
+        Invocation.method(
+          #create,
+          [
+            identifier,
+            configurationIdentifier,
+          ],
+        ),
+        returnValueForMissingStub: null,
+      );
   @override
-  void setUIDelegate(int? identifier, int? uiDelegateIdentifier) =>
+  void setUIDelegate(
+    int? identifier,
+    int? uiDelegateIdentifier,
+  ) =>
       super.noSuchMethod(
-          Invocation.method(#setUIDelegate, [identifier, uiDelegateIdentifier]),
-          returnValueForMissingStub: null);
+        Invocation.method(
+          #setUIDelegate,
+          [
+            identifier,
+            uiDelegateIdentifier,
+          ],
+        ),
+        returnValueForMissingStub: null,
+      );
   @override
   void setNavigationDelegate(
-          int? identifier, int? navigationDelegateIdentifier) =>
+    int? identifier,
+    int? navigationDelegateIdentifier,
+  ) =>
       super.noSuchMethod(
-          Invocation.method(#setNavigationDelegate,
-              [identifier, navigationDelegateIdentifier]),
-          returnValueForMissingStub: null);
+        Invocation.method(
+          #setNavigationDelegate,
+          [
+            identifier,
+            navigationDelegateIdentifier,
+          ],
+        ),
+        returnValueForMissingStub: null,
+      );
   @override
-  String? getUrl(int? identifier) =>
-      (super.noSuchMethod(Invocation.method(#getUrl, [identifier])) as String?);
+  String? getUrl(int? identifier) => (super.noSuchMethod(Invocation.method(
+        #getUrl,
+        [identifier],
+      )) as String?);
   @override
   double getEstimatedProgress(int? identifier) => (super.noSuchMethod(
-      Invocation.method(#getEstimatedProgress, [identifier]),
-      returnValue: 0.0) as double);
+        Invocation.method(
+          #getEstimatedProgress,
+          [identifier],
+        ),
+        returnValue: 0.0,
+      ) as double);
   @override
-  void loadRequest(int? identifier, _i4.NSUrlRequestData? request) =>
-      super.noSuchMethod(Invocation.method(#loadRequest, [identifier, request]),
-          returnValueForMissingStub: null);
-  @override
-  void loadHtmlString(int? identifier, String? string, String? baseUrl) =>
+  void loadRequest(
+    int? identifier,
+    _i4.NSUrlRequestData? request,
+  ) =>
       super.noSuchMethod(
-          Invocation.method(#loadHtmlString, [identifier, string, baseUrl]),
-          returnValueForMissingStub: null);
+        Invocation.method(
+          #loadRequest,
+          [
+            identifier,
+            request,
+          ],
+        ),
+        returnValueForMissingStub: null,
+      );
   @override
-  void loadFileUrl(int? identifier, String? url, String? readAccessUrl) =>
+  void loadHtmlString(
+    int? identifier,
+    String? string,
+    String? baseUrl,
+  ) =>
       super.noSuchMethod(
-          Invocation.method(#loadFileUrl, [identifier, url, readAccessUrl]),
-          returnValueForMissingStub: null);
+        Invocation.method(
+          #loadHtmlString,
+          [
+            identifier,
+            string,
+            baseUrl,
+          ],
+        ),
+        returnValueForMissingStub: null,
+      );
   @override
-  void loadFlutterAsset(int? identifier, String? key) => super.noSuchMethod(
-      Invocation.method(#loadFlutterAsset, [identifier, key]),
-      returnValueForMissingStub: null);
-  @override
-  bool canGoBack(int? identifier) =>
-      (super.noSuchMethod(Invocation.method(#canGoBack, [identifier]),
-          returnValue: false) as bool);
-  @override
-  bool canGoForward(int? identifier) =>
-      (super.noSuchMethod(Invocation.method(#canGoForward, [identifier]),
-          returnValue: false) as bool);
-  @override
-  void goBack(int? identifier) =>
-      super.noSuchMethod(Invocation.method(#goBack, [identifier]),
-          returnValueForMissingStub: null);
-  @override
-  void goForward(int? identifier) =>
-      super.noSuchMethod(Invocation.method(#goForward, [identifier]),
-          returnValueForMissingStub: null);
-  @override
-  void reload(int? identifier) =>
-      super.noSuchMethod(Invocation.method(#reload, [identifier]),
-          returnValueForMissingStub: null);
-  @override
-  String? getTitle(int? identifier) =>
-      (super.noSuchMethod(Invocation.method(#getTitle, [identifier]))
-          as String?);
-  @override
-  void setAllowsBackForwardNavigationGestures(int? identifier, bool? allow) =>
+  void loadFileUrl(
+    int? identifier,
+    String? url,
+    String? readAccessUrl,
+  ) =>
       super.noSuchMethod(
-          Invocation.method(
-              #setAllowsBackForwardNavigationGestures, [identifier, allow]),
-          returnValueForMissingStub: null);
+        Invocation.method(
+          #loadFileUrl,
+          [
+            identifier,
+            url,
+            readAccessUrl,
+          ],
+        ),
+        returnValueForMissingStub: null,
+      );
   @override
-  void setCustomUserAgent(int? identifier, String? userAgent) =>
+  void loadFlutterAsset(
+    int? identifier,
+    String? key,
+  ) =>
       super.noSuchMethod(
-          Invocation.method(#setCustomUserAgent, [identifier, userAgent]),
-          returnValueForMissingStub: null);
+        Invocation.method(
+          #loadFlutterAsset,
+          [
+            identifier,
+            key,
+          ],
+        ),
+        returnValueForMissingStub: null,
+      );
+  @override
+  bool canGoBack(int? identifier) => (super.noSuchMethod(
+        Invocation.method(
+          #canGoBack,
+          [identifier],
+        ),
+        returnValue: false,
+      ) as bool);
+  @override
+  bool canGoForward(int? identifier) => (super.noSuchMethod(
+        Invocation.method(
+          #canGoForward,
+          [identifier],
+        ),
+        returnValue: false,
+      ) as bool);
+  @override
+  void goBack(int? identifier) => super.noSuchMethod(
+        Invocation.method(
+          #goBack,
+          [identifier],
+        ),
+        returnValueForMissingStub: null,
+      );
+  @override
+  void goForward(int? identifier) => super.noSuchMethod(
+        Invocation.method(
+          #goForward,
+          [identifier],
+        ),
+        returnValueForMissingStub: null,
+      );
+  @override
+  void reload(int? identifier) => super.noSuchMethod(
+        Invocation.method(
+          #reload,
+          [identifier],
+        ),
+        returnValueForMissingStub: null,
+      );
+  @override
+  String? getTitle(int? identifier) => (super.noSuchMethod(Invocation.method(
+        #getTitle,
+        [identifier],
+      )) as String?);
+  @override
+  void setAllowsBackForwardNavigationGestures(
+    int? identifier,
+    bool? allow,
+  ) =>
+      super.noSuchMethod(
+        Invocation.method(
+          #setAllowsBackForwardNavigationGestures,
+          [
+            identifier,
+            allow,
+          ],
+        ),
+        returnValueForMissingStub: null,
+      );
+  @override
+  void setCustomUserAgent(
+    int? identifier,
+    String? userAgent,
+  ) =>
+      super.noSuchMethod(
+        Invocation.method(
+          #setCustomUserAgent,
+          [
+            identifier,
+            userAgent,
+          ],
+        ),
+        returnValueForMissingStub: null,
+      );
   @override
   _i3.Future<Object?> evaluateJavaScript(
-          int? identifier, String? javaScriptString) =>
+    int? identifier,
+    String? javaScriptString,
+  ) =>
       (super.noSuchMethod(
-          Invocation.method(
-              #evaluateJavaScript, [identifier, javaScriptString]),
-          returnValue: Future<Object?>.value()) as _i3.Future<Object?>);
+        Invocation.method(
+          #evaluateJavaScript,
+          [
+            identifier,
+            javaScriptString,
+          ],
+        ),
+        returnValue: _i3.Future<Object?>.value(),
+      ) as _i3.Future<Object?>);
 }
 
 /// A class which mocks [TestWKWebsiteDataStoreHostApi].
@@ -292,22 +549,42 @@
 
   @override
   void createFromWebViewConfiguration(
-          int? identifier, int? configurationIdentifier) =>
+    int? identifier,
+    int? configurationIdentifier,
+  ) =>
       super.noSuchMethod(
-          Invocation.method(#createFromWebViewConfiguration,
-              [identifier, configurationIdentifier]),
-          returnValueForMissingStub: null);
+        Invocation.method(
+          #createFromWebViewConfiguration,
+          [
+            identifier,
+            configurationIdentifier,
+          ],
+        ),
+        returnValueForMissingStub: null,
+      );
   @override
   void createDefaultDataStore(int? identifier) => super.noSuchMethod(
-      Invocation.method(#createDefaultDataStore, [identifier]),
-      returnValueForMissingStub: null);
+        Invocation.method(
+          #createDefaultDataStore,
+          [identifier],
+        ),
+        returnValueForMissingStub: null,
+      );
   @override
   _i3.Future<bool> removeDataOfTypes(
-          int? identifier,
-          List<_i4.WKWebsiteDataTypeEnumData?>? dataTypes,
-          double? modificationTimeInSecondsSinceEpoch) =>
+    int? identifier,
+    List<_i4.WKWebsiteDataTypeEnumData?>? dataTypes,
+    double? modificationTimeInSecondsSinceEpoch,
+  ) =>
       (super.noSuchMethod(
-          Invocation.method(#removeDataOfTypes,
-              [identifier, dataTypes, modificationTimeInSecondsSinceEpoch]),
-          returnValue: Future<bool>.value(false)) as _i3.Future<bool>);
+        Invocation.method(
+          #removeDataOfTypes,
+          [
+            identifier,
+            dataTypes,
+            modificationTimeInSecondsSinceEpoch,
+          ],
+        ),
+        returnValue: _i3.Future<bool>.value(false),
+      ) as _i3.Future<bool>);
 }
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/test/src/web_kit_cookie_manager_test.mocks.dart b/packages/webview_flutter/webview_flutter_wkwebview/test/src/web_kit_cookie_manager_test.mocks.dart
deleted file mode 100644
index e44e7b1..0000000
--- a/packages/webview_flutter/webview_flutter_wkwebview/test/src/web_kit_cookie_manager_test.mocks.dart
+++ /dev/null
@@ -1,100 +0,0 @@
-// Mocks generated by Mockito 5.2.0 from annotations
-// in webview_flutter_wkwebview/example/ios/.symlinks/plugins/webview_flutter_wkwebview/test/src/web_kit_cookie_manager_test.dart.
-// Do not manually edit this file.
-
-import 'dart:async' as _i3;
-
-import 'package:mockito/mockito.dart' as _i1;
-import 'package:webview_flutter_wkwebview/src/foundation/foundation.dart'
-    as _i4;
-import 'package:webview_flutter_wkwebview/src/web_kit/web_kit.dart' as _i2;
-
-// ignore_for_file: type=lint
-// ignore_for_file: avoid_redundant_argument_values
-// ignore_for_file: avoid_setters_without_getters
-// ignore_for_file: comment_references
-// ignore_for_file: implementation_imports
-// ignore_for_file: invalid_use_of_visible_for_testing_member
-// ignore_for_file: prefer_const_constructors
-// ignore_for_file: unnecessary_parenthesis
-// ignore_for_file: camel_case_types
-
-class _FakeWKHttpCookieStore_0 extends _i1.Fake
-    implements _i2.WKHttpCookieStore {}
-
-class _FakeWKWebsiteDataStore_1 extends _i1.Fake
-    implements _i2.WKWebsiteDataStore {}
-
-/// A class which mocks [WKHttpCookieStore].
-///
-/// See the documentation for Mockito's code generation for more information.
-// ignore: must_be_immutable
-class MockWKHttpCookieStore extends _i1.Mock implements _i2.WKHttpCookieStore {
-  MockWKHttpCookieStore() {
-    _i1.throwOnMissingStub(this);
-  }
-
-  @override
-  _i3.Future<void> setCookie(_i4.NSHttpCookie? cookie) =>
-      (super.noSuchMethod(Invocation.method(#setCookie, [cookie]),
-          returnValue: Future<void>.value(),
-          returnValueForMissingStub: Future<void>.value()) as _i3.Future<void>);
-  @override
-  _i2.WKHttpCookieStore copy() =>
-      (super.noSuchMethod(Invocation.method(#copy, []),
-          returnValue: _FakeWKHttpCookieStore_0()) as _i2.WKHttpCookieStore);
-  @override
-  _i3.Future<void> addObserver(_i4.NSObject? observer,
-          {String? keyPath, Set<_i4.NSKeyValueObservingOptions>? options}) =>
-      (super.noSuchMethod(
-          Invocation.method(
-              #addObserver, [observer], {#keyPath: keyPath, #options: options}),
-          returnValue: Future<void>.value(),
-          returnValueForMissingStub: Future<void>.value()) as _i3.Future<void>);
-  @override
-  _i3.Future<void> removeObserver(_i4.NSObject? observer, {String? keyPath}) =>
-      (super.noSuchMethod(
-          Invocation.method(#removeObserver, [observer], {#keyPath: keyPath}),
-          returnValue: Future<void>.value(),
-          returnValueForMissingStub: Future<void>.value()) as _i3.Future<void>);
-}
-
-/// A class which mocks [WKWebsiteDataStore].
-///
-/// See the documentation for Mockito's code generation for more information.
-// ignore: must_be_immutable
-class MockWKWebsiteDataStore extends _i1.Mock
-    implements _i2.WKWebsiteDataStore {
-  MockWKWebsiteDataStore() {
-    _i1.throwOnMissingStub(this);
-  }
-
-  @override
-  _i2.WKHttpCookieStore get httpCookieStore =>
-      (super.noSuchMethod(Invocation.getter(#httpCookieStore),
-          returnValue: _FakeWKHttpCookieStore_0()) as _i2.WKHttpCookieStore);
-  @override
-  _i3.Future<bool> removeDataOfTypes(
-          Set<_i2.WKWebsiteDataType>? dataTypes, DateTime? since) =>
-      (super.noSuchMethod(
-          Invocation.method(#removeDataOfTypes, [dataTypes, since]),
-          returnValue: Future<bool>.value(false)) as _i3.Future<bool>);
-  @override
-  _i2.WKWebsiteDataStore copy() =>
-      (super.noSuchMethod(Invocation.method(#copy, []),
-          returnValue: _FakeWKWebsiteDataStore_1()) as _i2.WKWebsiteDataStore);
-  @override
-  _i3.Future<void> addObserver(_i4.NSObject? observer,
-          {String? keyPath, Set<_i4.NSKeyValueObservingOptions>? options}) =>
-      (super.noSuchMethod(
-          Invocation.method(
-              #addObserver, [observer], {#keyPath: keyPath, #options: options}),
-          returnValue: Future<void>.value(),
-          returnValueForMissingStub: Future<void>.value()) as _i3.Future<void>);
-  @override
-  _i3.Future<void> removeObserver(_i4.NSObject? observer, {String? keyPath}) =>
-      (super.noSuchMethod(
-          Invocation.method(#removeObserver, [observer], {#keyPath: keyPath}),
-          returnValue: Future<void>.value(),
-          returnValueForMissingStub: Future<void>.value()) as _i3.Future<void>);
-}
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/test/src/web_kit_webview_widget_test.mocks.dart b/packages/webview_flutter/webview_flutter_wkwebview/test/src/web_kit_webview_widget_test.mocks.dart
deleted file mode 100644
index f216711..0000000
--- a/packages/webview_flutter/webview_flutter_wkwebview/test/src/web_kit_webview_widget_test.mocks.dart
+++ /dev/null
@@ -1,648 +0,0 @@
-// Mocks generated by Mockito 5.2.0 from annotations
-// in webview_flutter_wkwebview/example/ios/.symlinks/plugins/webview_flutter_wkwebview/test/src/web_kit_webview_widget_test.dart.
-// Do not manually edit this file.
-
-import 'dart:async' as _i5;
-import 'dart:math' as _i2;
-import 'dart:ui' as _i6;
-
-import 'package:mockito/mockito.dart' as _i1;
-import 'package:webview_flutter_platform_interface/src/types/javascript_channel.dart'
-    as _i9;
-import 'package:webview_flutter_platform_interface/src/types/types.dart'
-    as _i10;
-import 'package:webview_flutter_platform_interface/webview_flutter_platform_interface.dart'
-    as _i8;
-import 'package:webview_flutter_wkwebview/src/foundation/foundation.dart'
-    as _i7;
-import 'package:webview_flutter_wkwebview/src/ui_kit/ui_kit.dart' as _i3;
-import 'package:webview_flutter_wkwebview/src/web_kit/web_kit.dart' as _i4;
-import 'package:webview_flutter_wkwebview/src/web_kit_webview_widget.dart'
-    as _i11;
-
-// ignore_for_file: type=lint
-// ignore_for_file: avoid_redundant_argument_values
-// ignore_for_file: avoid_setters_without_getters
-// ignore_for_file: comment_references
-// ignore_for_file: implementation_imports
-// ignore_for_file: invalid_use_of_visible_for_testing_member
-// ignore_for_file: prefer_const_constructors
-// ignore_for_file: unnecessary_parenthesis
-// ignore_for_file: camel_case_types
-
-class _FakePoint_0<T extends num> extends _i1.Fake implements _i2.Point<T> {}
-
-class _FakeUIScrollView_1 extends _i1.Fake implements _i3.UIScrollView {}
-
-class _FakeWKNavigationDelegate_2 extends _i1.Fake
-    implements _i4.WKNavigationDelegate {}
-
-class _FakeWKPreferences_3 extends _i1.Fake implements _i4.WKPreferences {}
-
-class _FakeWKScriptMessageHandler_4 extends _i1.Fake
-    implements _i4.WKScriptMessageHandler {}
-
-class _FakeWKWebViewConfiguration_5 extends _i1.Fake
-    implements _i4.WKWebViewConfiguration {}
-
-class _FakeWKWebView_6 extends _i1.Fake implements _i4.WKWebView {}
-
-class _FakeWKUserContentController_7 extends _i1.Fake
-    implements _i4.WKUserContentController {}
-
-class _FakeWKWebsiteDataStore_8 extends _i1.Fake
-    implements _i4.WKWebsiteDataStore {}
-
-class _FakeWKHttpCookieStore_9 extends _i1.Fake
-    implements _i4.WKHttpCookieStore {}
-
-class _FakeWKUIDelegate_10 extends _i1.Fake implements _i4.WKUIDelegate {}
-
-/// A class which mocks [UIScrollView].
-///
-/// See the documentation for Mockito's code generation for more information.
-// ignore: must_be_immutable
-class MockUIScrollView extends _i1.Mock implements _i3.UIScrollView {
-  MockUIScrollView() {
-    _i1.throwOnMissingStub(this);
-  }
-
-  @override
-  _i5.Future<_i2.Point<double>> getContentOffset() => (super.noSuchMethod(
-          Invocation.method(#getContentOffset, []),
-          returnValue: Future<_i2.Point<double>>.value(_FakePoint_0<double>()))
-      as _i5.Future<_i2.Point<double>>);
-  @override
-  _i5.Future<void> scrollBy(_i2.Point<double>? offset) =>
-      (super.noSuchMethod(Invocation.method(#scrollBy, [offset]),
-          returnValue: Future<void>.value(),
-          returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
-  @override
-  _i5.Future<void> setContentOffset(_i2.Point<double>? offset) =>
-      (super.noSuchMethod(Invocation.method(#setContentOffset, [offset]),
-          returnValue: Future<void>.value(),
-          returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
-  @override
-  _i3.UIScrollView copy() => (super.noSuchMethod(Invocation.method(#copy, []),
-      returnValue: _FakeUIScrollView_1()) as _i3.UIScrollView);
-  @override
-  _i5.Future<void> setBackgroundColor(_i6.Color? color) =>
-      (super.noSuchMethod(Invocation.method(#setBackgroundColor, [color]),
-          returnValue: Future<void>.value(),
-          returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
-  @override
-  _i5.Future<void> setOpaque(bool? opaque) =>
-      (super.noSuchMethod(Invocation.method(#setOpaque, [opaque]),
-          returnValue: Future<void>.value(),
-          returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
-  @override
-  _i5.Future<void> addObserver(_i7.NSObject? observer,
-          {String? keyPath, Set<_i7.NSKeyValueObservingOptions>? options}) =>
-      (super.noSuchMethod(
-          Invocation.method(
-              #addObserver, [observer], {#keyPath: keyPath, #options: options}),
-          returnValue: Future<void>.value(),
-          returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
-  @override
-  _i5.Future<void> removeObserver(_i7.NSObject? observer, {String? keyPath}) =>
-      (super.noSuchMethod(
-          Invocation.method(#removeObserver, [observer], {#keyPath: keyPath}),
-          returnValue: Future<void>.value(),
-          returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
-}
-
-/// A class which mocks [WKNavigationDelegate].
-///
-/// See the documentation for Mockito's code generation for more information.
-// ignore: must_be_immutable
-class MockWKNavigationDelegate extends _i1.Mock
-    implements _i4.WKNavigationDelegate {
-  MockWKNavigationDelegate() {
-    _i1.throwOnMissingStub(this);
-  }
-
-  @override
-  _i4.WKNavigationDelegate copy() => (super.noSuchMethod(
-      Invocation.method(#copy, []),
-      returnValue: _FakeWKNavigationDelegate_2()) as _i4.WKNavigationDelegate);
-  @override
-  _i5.Future<void> addObserver(_i7.NSObject? observer,
-          {String? keyPath, Set<_i7.NSKeyValueObservingOptions>? options}) =>
-      (super.noSuchMethod(
-          Invocation.method(
-              #addObserver, [observer], {#keyPath: keyPath, #options: options}),
-          returnValue: Future<void>.value(),
-          returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
-  @override
-  _i5.Future<void> removeObserver(_i7.NSObject? observer, {String? keyPath}) =>
-      (super.noSuchMethod(
-          Invocation.method(#removeObserver, [observer], {#keyPath: keyPath}),
-          returnValue: Future<void>.value(),
-          returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
-}
-
-/// A class which mocks [WKPreferences].
-///
-/// See the documentation for Mockito's code generation for more information.
-// ignore: must_be_immutable
-class MockWKPreferences extends _i1.Mock implements _i4.WKPreferences {
-  MockWKPreferences() {
-    _i1.throwOnMissingStub(this);
-  }
-
-  @override
-  _i5.Future<void> setJavaScriptEnabled(bool? enabled) =>
-      (super.noSuchMethod(Invocation.method(#setJavaScriptEnabled, [enabled]),
-          returnValue: Future<void>.value(),
-          returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
-  @override
-  _i4.WKPreferences copy() => (super.noSuchMethod(Invocation.method(#copy, []),
-      returnValue: _FakeWKPreferences_3()) as _i4.WKPreferences);
-  @override
-  _i5.Future<void> addObserver(_i7.NSObject? observer,
-          {String? keyPath, Set<_i7.NSKeyValueObservingOptions>? options}) =>
-      (super.noSuchMethod(
-          Invocation.method(
-              #addObserver, [observer], {#keyPath: keyPath, #options: options}),
-          returnValue: Future<void>.value(),
-          returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
-  @override
-  _i5.Future<void> removeObserver(_i7.NSObject? observer, {String? keyPath}) =>
-      (super.noSuchMethod(
-          Invocation.method(#removeObserver, [observer], {#keyPath: keyPath}),
-          returnValue: Future<void>.value(),
-          returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
-}
-
-/// A class which mocks [WKScriptMessageHandler].
-///
-/// See the documentation for Mockito's code generation for more information.
-// ignore: must_be_immutable
-class MockWKScriptMessageHandler extends _i1.Mock
-    implements _i4.WKScriptMessageHandler {
-  MockWKScriptMessageHandler() {
-    _i1.throwOnMissingStub(this);
-  }
-
-  @override
-  void Function(_i4.WKUserContentController, _i4.WKScriptMessage)
-      get didReceiveScriptMessage =>
-          (super.noSuchMethod(Invocation.getter(#didReceiveScriptMessage),
-              returnValue: (_i4.WKUserContentController userContentController,
-                  _i4.WKScriptMessage message) {}) as void Function(
-              _i4.WKUserContentController, _i4.WKScriptMessage));
-  @override
-  _i4.WKScriptMessageHandler copy() =>
-      (super.noSuchMethod(Invocation.method(#copy, []),
-              returnValue: _FakeWKScriptMessageHandler_4())
-          as _i4.WKScriptMessageHandler);
-  @override
-  _i5.Future<void> addObserver(_i7.NSObject? observer,
-          {String? keyPath, Set<_i7.NSKeyValueObservingOptions>? options}) =>
-      (super.noSuchMethod(
-          Invocation.method(
-              #addObserver, [observer], {#keyPath: keyPath, #options: options}),
-          returnValue: Future<void>.value(),
-          returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
-  @override
-  _i5.Future<void> removeObserver(_i7.NSObject? observer, {String? keyPath}) =>
-      (super.noSuchMethod(
-          Invocation.method(#removeObserver, [observer], {#keyPath: keyPath}),
-          returnValue: Future<void>.value(),
-          returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
-}
-
-/// A class which mocks [WKWebView].
-///
-/// See the documentation for Mockito's code generation for more information.
-// ignore: must_be_immutable
-class MockWKWebView extends _i1.Mock implements _i4.WKWebView {
-  MockWKWebView() {
-    _i1.throwOnMissingStub(this);
-  }
-
-  @override
-  _i4.WKWebViewConfiguration get configuration =>
-      (super.noSuchMethod(Invocation.getter(#configuration),
-              returnValue: _FakeWKWebViewConfiguration_5())
-          as _i4.WKWebViewConfiguration);
-  @override
-  _i3.UIScrollView get scrollView =>
-      (super.noSuchMethod(Invocation.getter(#scrollView),
-          returnValue: _FakeUIScrollView_1()) as _i3.UIScrollView);
-  @override
-  _i5.Future<void> setUIDelegate(_i4.WKUIDelegate? delegate) =>
-      (super.noSuchMethod(Invocation.method(#setUIDelegate, [delegate]),
-          returnValue: Future<void>.value(),
-          returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
-  @override
-  _i5.Future<void> setNavigationDelegate(_i4.WKNavigationDelegate? delegate) =>
-      (super.noSuchMethod(Invocation.method(#setNavigationDelegate, [delegate]),
-          returnValue: Future<void>.value(),
-          returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
-  @override
-  _i5.Future<String?> getUrl() =>
-      (super.noSuchMethod(Invocation.method(#getUrl, []),
-          returnValue: Future<String?>.value()) as _i5.Future<String?>);
-  @override
-  _i5.Future<double> getEstimatedProgress() =>
-      (super.noSuchMethod(Invocation.method(#getEstimatedProgress, []),
-          returnValue: Future<double>.value(0.0)) as _i5.Future<double>);
-  @override
-  _i5.Future<void> loadRequest(_i7.NSUrlRequest? request) =>
-      (super.noSuchMethod(Invocation.method(#loadRequest, [request]),
-          returnValue: Future<void>.value(),
-          returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
-  @override
-  _i5.Future<void> loadHtmlString(String? string, {String? baseUrl}) =>
-      (super.noSuchMethod(
-          Invocation.method(#loadHtmlString, [string], {#baseUrl: baseUrl}),
-          returnValue: Future<void>.value(),
-          returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
-  @override
-  _i5.Future<void> loadFileUrl(String? url, {String? readAccessUrl}) =>
-      (super.noSuchMethod(
-          Invocation.method(
-              #loadFileUrl, [url], {#readAccessUrl: readAccessUrl}),
-          returnValue: Future<void>.value(),
-          returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
-  @override
-  _i5.Future<void> loadFlutterAsset(String? key) =>
-      (super.noSuchMethod(Invocation.method(#loadFlutterAsset, [key]),
-          returnValue: Future<void>.value(),
-          returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
-  @override
-  _i5.Future<bool> canGoBack() =>
-      (super.noSuchMethod(Invocation.method(#canGoBack, []),
-          returnValue: Future<bool>.value(false)) as _i5.Future<bool>);
-  @override
-  _i5.Future<bool> canGoForward() =>
-      (super.noSuchMethod(Invocation.method(#canGoForward, []),
-          returnValue: Future<bool>.value(false)) as _i5.Future<bool>);
-  @override
-  _i5.Future<void> goBack() =>
-      (super.noSuchMethod(Invocation.method(#goBack, []),
-          returnValue: Future<void>.value(),
-          returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
-  @override
-  _i5.Future<void> goForward() =>
-      (super.noSuchMethod(Invocation.method(#goForward, []),
-          returnValue: Future<void>.value(),
-          returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
-  @override
-  _i5.Future<void> reload() =>
-      (super.noSuchMethod(Invocation.method(#reload, []),
-          returnValue: Future<void>.value(),
-          returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
-  @override
-  _i5.Future<String?> getTitle() =>
-      (super.noSuchMethod(Invocation.method(#getTitle, []),
-          returnValue: Future<String?>.value()) as _i5.Future<String?>);
-  @override
-  _i5.Future<void> setAllowsBackForwardNavigationGestures(bool? allow) =>
-      (super.noSuchMethod(
-          Invocation.method(#setAllowsBackForwardNavigationGestures, [allow]),
-          returnValue: Future<void>.value(),
-          returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
-  @override
-  _i5.Future<void> setCustomUserAgent(String? userAgent) =>
-      (super.noSuchMethod(Invocation.method(#setCustomUserAgent, [userAgent]),
-          returnValue: Future<void>.value(),
-          returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
-  @override
-  _i5.Future<Object?> evaluateJavaScript(String? javaScriptString) => (super
-      .noSuchMethod(Invocation.method(#evaluateJavaScript, [javaScriptString]),
-          returnValue: Future<Object?>.value()) as _i5.Future<Object?>);
-  @override
-  _i4.WKWebView copy() => (super.noSuchMethod(Invocation.method(#copy, []),
-      returnValue: _FakeWKWebView_6()) as _i4.WKWebView);
-  @override
-  _i5.Future<void> setBackgroundColor(_i6.Color? color) =>
-      (super.noSuchMethod(Invocation.method(#setBackgroundColor, [color]),
-          returnValue: Future<void>.value(),
-          returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
-  @override
-  _i5.Future<void> setOpaque(bool? opaque) =>
-      (super.noSuchMethod(Invocation.method(#setOpaque, [opaque]),
-          returnValue: Future<void>.value(),
-          returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
-  @override
-  _i5.Future<void> addObserver(_i7.NSObject? observer,
-          {String? keyPath, Set<_i7.NSKeyValueObservingOptions>? options}) =>
-      (super.noSuchMethod(
-          Invocation.method(
-              #addObserver, [observer], {#keyPath: keyPath, #options: options}),
-          returnValue: Future<void>.value(),
-          returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
-  @override
-  _i5.Future<void> removeObserver(_i7.NSObject? observer, {String? keyPath}) =>
-      (super.noSuchMethod(
-          Invocation.method(#removeObserver, [observer], {#keyPath: keyPath}),
-          returnValue: Future<void>.value(),
-          returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
-}
-
-/// A class which mocks [WKWebViewConfiguration].
-///
-/// See the documentation for Mockito's code generation for more information.
-// ignore: must_be_immutable
-class MockWKWebViewConfiguration extends _i1.Mock
-    implements _i4.WKWebViewConfiguration {
-  MockWKWebViewConfiguration() {
-    _i1.throwOnMissingStub(this);
-  }
-
-  @override
-  _i4.WKUserContentController get userContentController =>
-      (super.noSuchMethod(Invocation.getter(#userContentController),
-              returnValue: _FakeWKUserContentController_7())
-          as _i4.WKUserContentController);
-  @override
-  _i4.WKPreferences get preferences =>
-      (super.noSuchMethod(Invocation.getter(#preferences),
-          returnValue: _FakeWKPreferences_3()) as _i4.WKPreferences);
-  @override
-  _i4.WKWebsiteDataStore get websiteDataStore =>
-      (super.noSuchMethod(Invocation.getter(#websiteDataStore),
-          returnValue: _FakeWKWebsiteDataStore_8()) as _i4.WKWebsiteDataStore);
-  @override
-  _i5.Future<void> setAllowsInlineMediaPlayback(bool? allow) => (super
-      .noSuchMethod(Invocation.method(#setAllowsInlineMediaPlayback, [allow]),
-          returnValue: Future<void>.value(),
-          returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
-  @override
-  _i5.Future<void> setMediaTypesRequiringUserActionForPlayback(
-          Set<_i4.WKAudiovisualMediaType>? types) =>
-      (super.noSuchMethod(
-          Invocation.method(
-              #setMediaTypesRequiringUserActionForPlayback, [types]),
-          returnValue: Future<void>.value(),
-          returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
-  @override
-  _i4.WKWebViewConfiguration copy() =>
-      (super.noSuchMethod(Invocation.method(#copy, []),
-              returnValue: _FakeWKWebViewConfiguration_5())
-          as _i4.WKWebViewConfiguration);
-  @override
-  _i5.Future<void> addObserver(_i7.NSObject? observer,
-          {String? keyPath, Set<_i7.NSKeyValueObservingOptions>? options}) =>
-      (super.noSuchMethod(
-          Invocation.method(
-              #addObserver, [observer], {#keyPath: keyPath, #options: options}),
-          returnValue: Future<void>.value(),
-          returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
-  @override
-  _i5.Future<void> removeObserver(_i7.NSObject? observer, {String? keyPath}) =>
-      (super.noSuchMethod(
-          Invocation.method(#removeObserver, [observer], {#keyPath: keyPath}),
-          returnValue: Future<void>.value(),
-          returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
-}
-
-/// A class which mocks [WKWebsiteDataStore].
-///
-/// See the documentation for Mockito's code generation for more information.
-// ignore: must_be_immutable
-class MockWKWebsiteDataStore extends _i1.Mock
-    implements _i4.WKWebsiteDataStore {
-  MockWKWebsiteDataStore() {
-    _i1.throwOnMissingStub(this);
-  }
-
-  @override
-  _i4.WKHttpCookieStore get httpCookieStore =>
-      (super.noSuchMethod(Invocation.getter(#httpCookieStore),
-          returnValue: _FakeWKHttpCookieStore_9()) as _i4.WKHttpCookieStore);
-  @override
-  _i5.Future<bool> removeDataOfTypes(
-          Set<_i4.WKWebsiteDataType>? dataTypes, DateTime? since) =>
-      (super.noSuchMethod(
-          Invocation.method(#removeDataOfTypes, [dataTypes, since]),
-          returnValue: Future<bool>.value(false)) as _i5.Future<bool>);
-  @override
-  _i4.WKWebsiteDataStore copy() =>
-      (super.noSuchMethod(Invocation.method(#copy, []),
-          returnValue: _FakeWKWebsiteDataStore_8()) as _i4.WKWebsiteDataStore);
-  @override
-  _i5.Future<void> addObserver(_i7.NSObject? observer,
-          {String? keyPath, Set<_i7.NSKeyValueObservingOptions>? options}) =>
-      (super.noSuchMethod(
-          Invocation.method(
-              #addObserver, [observer], {#keyPath: keyPath, #options: options}),
-          returnValue: Future<void>.value(),
-          returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
-  @override
-  _i5.Future<void> removeObserver(_i7.NSObject? observer, {String? keyPath}) =>
-      (super.noSuchMethod(
-          Invocation.method(#removeObserver, [observer], {#keyPath: keyPath}),
-          returnValue: Future<void>.value(),
-          returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
-}
-
-/// A class which mocks [WKUIDelegate].
-///
-/// See the documentation for Mockito's code generation for more information.
-// ignore: must_be_immutable
-class MockWKUIDelegate extends _i1.Mock implements _i4.WKUIDelegate {
-  MockWKUIDelegate() {
-    _i1.throwOnMissingStub(this);
-  }
-
-  @override
-  _i4.WKUIDelegate copy() => (super.noSuchMethod(Invocation.method(#copy, []),
-      returnValue: _FakeWKUIDelegate_10()) as _i4.WKUIDelegate);
-  @override
-  _i5.Future<void> addObserver(_i7.NSObject? observer,
-          {String? keyPath, Set<_i7.NSKeyValueObservingOptions>? options}) =>
-      (super.noSuchMethod(
-          Invocation.method(
-              #addObserver, [observer], {#keyPath: keyPath, #options: options}),
-          returnValue: Future<void>.value(),
-          returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
-  @override
-  _i5.Future<void> removeObserver(_i7.NSObject? observer, {String? keyPath}) =>
-      (super.noSuchMethod(
-          Invocation.method(#removeObserver, [observer], {#keyPath: keyPath}),
-          returnValue: Future<void>.value(),
-          returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
-}
-
-/// A class which mocks [WKUserContentController].
-///
-/// See the documentation for Mockito's code generation for more information.
-// ignore: must_be_immutable
-class MockWKUserContentController extends _i1.Mock
-    implements _i4.WKUserContentController {
-  MockWKUserContentController() {
-    _i1.throwOnMissingStub(this);
-  }
-
-  @override
-  _i5.Future<void> addScriptMessageHandler(
-          _i4.WKScriptMessageHandler? handler, String? name) =>
-      (super.noSuchMethod(
-          Invocation.method(#addScriptMessageHandler, [handler, name]),
-          returnValue: Future<void>.value(),
-          returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
-  @override
-  _i5.Future<void> removeScriptMessageHandler(String? name) => (super
-      .noSuchMethod(Invocation.method(#removeScriptMessageHandler, [name]),
-          returnValue: Future<void>.value(),
-          returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
-  @override
-  _i5.Future<void> removeAllScriptMessageHandlers() => (super.noSuchMethod(
-      Invocation.method(#removeAllScriptMessageHandlers, []),
-      returnValue: Future<void>.value(),
-      returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
-  @override
-  _i5.Future<void> addUserScript(_i4.WKUserScript? userScript) =>
-      (super.noSuchMethod(Invocation.method(#addUserScript, [userScript]),
-          returnValue: Future<void>.value(),
-          returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
-  @override
-  _i5.Future<void> removeAllUserScripts() =>
-      (super.noSuchMethod(Invocation.method(#removeAllUserScripts, []),
-          returnValue: Future<void>.value(),
-          returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
-  @override
-  _i4.WKUserContentController copy() =>
-      (super.noSuchMethod(Invocation.method(#copy, []),
-              returnValue: _FakeWKUserContentController_7())
-          as _i4.WKUserContentController);
-  @override
-  _i5.Future<void> addObserver(_i7.NSObject? observer,
-          {String? keyPath, Set<_i7.NSKeyValueObservingOptions>? options}) =>
-      (super.noSuchMethod(
-          Invocation.method(
-              #addObserver, [observer], {#keyPath: keyPath, #options: options}),
-          returnValue: Future<void>.value(),
-          returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
-  @override
-  _i5.Future<void> removeObserver(_i7.NSObject? observer, {String? keyPath}) =>
-      (super.noSuchMethod(
-          Invocation.method(#removeObserver, [observer], {#keyPath: keyPath}),
-          returnValue: Future<void>.value(),
-          returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
-}
-
-/// A class which mocks [JavascriptChannelRegistry].
-///
-/// See the documentation for Mockito's code generation for more information.
-class MockJavascriptChannelRegistry extends _i1.Mock
-    implements _i8.JavascriptChannelRegistry {
-  MockJavascriptChannelRegistry() {
-    _i1.throwOnMissingStub(this);
-  }
-
-  @override
-  Map<String, _i9.JavascriptChannel> get channels =>
-      (super.noSuchMethod(Invocation.getter(#channels),
-              returnValue: <String, _i9.JavascriptChannel>{})
-          as Map<String, _i9.JavascriptChannel>);
-  @override
-  void onJavascriptChannelMessage(String? channel, String? message) =>
-      super.noSuchMethod(
-          Invocation.method(#onJavascriptChannelMessage, [channel, message]),
-          returnValueForMissingStub: null);
-  @override
-  void updateJavascriptChannelsFromSet(Set<_i9.JavascriptChannel>? channels) =>
-      super.noSuchMethod(
-          Invocation.method(#updateJavascriptChannelsFromSet, [channels]),
-          returnValueForMissingStub: null);
-}
-
-/// A class which mocks [WebViewPlatformCallbacksHandler].
-///
-/// See the documentation for Mockito's code generation for more information.
-class MockWebViewPlatformCallbacksHandler extends _i1.Mock
-    implements _i8.WebViewPlatformCallbacksHandler {
-  MockWebViewPlatformCallbacksHandler() {
-    _i1.throwOnMissingStub(this);
-  }
-
-  @override
-  _i5.FutureOr<bool> onNavigationRequest({String? url, bool? isForMainFrame}) =>
-      (super.noSuchMethod(
-          Invocation.method(#onNavigationRequest, [],
-              {#url: url, #isForMainFrame: isForMainFrame}),
-          returnValue: Future<bool>.value(false)) as _i5.FutureOr<bool>);
-  @override
-  void onPageStarted(String? url) =>
-      super.noSuchMethod(Invocation.method(#onPageStarted, [url]),
-          returnValueForMissingStub: null);
-  @override
-  void onPageFinished(String? url) =>
-      super.noSuchMethod(Invocation.method(#onPageFinished, [url]),
-          returnValueForMissingStub: null);
-  @override
-  void onProgress(int? progress) =>
-      super.noSuchMethod(Invocation.method(#onProgress, [progress]),
-          returnValueForMissingStub: null);
-  @override
-  void onWebResourceError(_i10.WebResourceError? error) =>
-      super.noSuchMethod(Invocation.method(#onWebResourceError, [error]),
-          returnValueForMissingStub: null);
-}
-
-/// A class which mocks [WebViewWidgetProxy].
-///
-/// See the documentation for Mockito's code generation for more information.
-class MockWebViewWidgetProxy extends _i1.Mock
-    implements _i11.WebViewWidgetProxy {
-  MockWebViewWidgetProxy() {
-    _i1.throwOnMissingStub(this);
-  }
-
-  @override
-  _i4.WKWebView createWebView(_i4.WKWebViewConfiguration? configuration,
-          {void Function(
-                  String, _i7.NSObject, Map<_i7.NSKeyValueChangeKey, Object?>)?
-              observeValue}) =>
-      (super.noSuchMethod(
-          Invocation.method(
-              #createWebView, [configuration], {#observeValue: observeValue}),
-          returnValue: _FakeWKWebView_6()) as _i4.WKWebView);
-  @override
-  _i4.WKScriptMessageHandler createScriptMessageHandler(
-          {void Function(_i4.WKUserContentController, _i4.WKScriptMessage)?
-              didReceiveScriptMessage}) =>
-      (super.noSuchMethod(
-              Invocation.method(#createScriptMessageHandler, [],
-                  {#didReceiveScriptMessage: didReceiveScriptMessage}),
-              returnValue: _FakeWKScriptMessageHandler_4())
-          as _i4.WKScriptMessageHandler);
-  @override
-  _i4.WKUIDelegate createUIDelgate(
-          {void Function(_i4.WKWebView, _i4.WKWebViewConfiguration,
-                  _i4.WKNavigationAction)?
-              onCreateWebView}) =>
-      (super.noSuchMethod(
-          Invocation.method(
-              #createUIDelgate, [], {#onCreateWebView: onCreateWebView}),
-          returnValue: _FakeWKUIDelegate_10()) as _i4.WKUIDelegate);
-  @override
-  _i4.WKNavigationDelegate createNavigationDelegate(
-          {void Function(_i4.WKWebView, String?)? didFinishNavigation,
-          void Function(_i4.WKWebView, String?)? didStartProvisionalNavigation,
-          _i5.Future<_i4.WKNavigationActionPolicy> Function(
-                  _i4.WKWebView, _i4.WKNavigationAction)?
-              decidePolicyForNavigationAction,
-          void Function(_i4.WKWebView, _i7.NSError)? didFailNavigation,
-          void Function(_i4.WKWebView, _i7.NSError)?
-              didFailProvisionalNavigation,
-          void Function(_i4.WKWebView)?
-              webViewWebContentProcessDidTerminate}) =>
-      (super.noSuchMethod(
-              Invocation.method(#createNavigationDelegate, [], {
-                #didFinishNavigation: didFinishNavigation,
-                #didStartProvisionalNavigation: didStartProvisionalNavigation,
-                #decidePolicyForNavigationAction:
-                    decidePolicyForNavigationAction,
-                #didFailNavigation: didFailNavigation,
-                #didFailProvisionalNavigation: didFailProvisionalNavigation,
-                #webViewWebContentProcessDidTerminate:
-                    webViewWebContentProcessDidTerminate
-              }),
-              returnValue: _FakeWKNavigationDelegate_2())
-          as _i4.WKNavigationDelegate);
-}
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/test/v4/webkit_webview_controller_test.mocks.dart b/packages/webview_flutter/webview_flutter_wkwebview/test/v4/webkit_webview_controller_test.mocks.dart
deleted file mode 100644
index 17d4791..0000000
--- a/packages/webview_flutter/webview_flutter_wkwebview/test/v4/webkit_webview_controller_test.mocks.dart
+++ /dev/null
@@ -1,414 +0,0 @@
-// Mocks generated by Mockito 5.2.0 from annotations
-// in webview_flutter_wkwebview/test/v4/webkit_webview_controller_test.dart.
-// Do not manually edit this file.
-
-import 'dart:async' as _i5;
-import 'dart:math' as _i2;
-import 'dart:ui' as _i6;
-
-import 'package:mockito/mockito.dart' as _i1;
-import 'package:webview_flutter_wkwebview/src/foundation/foundation.dart'
-    as _i7;
-import 'package:webview_flutter_wkwebview/src/ui_kit/ui_kit.dart' as _i3;
-import 'package:webview_flutter_wkwebview/src/web_kit/web_kit.dart' as _i4;
-
-// ignore_for_file: type=lint
-// ignore_for_file: avoid_redundant_argument_values
-// ignore_for_file: avoid_setters_without_getters
-// ignore_for_file: comment_references
-// ignore_for_file: implementation_imports
-// ignore_for_file: invalid_use_of_visible_for_testing_member
-// ignore_for_file: prefer_const_constructors
-// ignore_for_file: unnecessary_parenthesis
-// ignore_for_file: camel_case_types
-
-class _FakePoint_0<T extends num> extends _i1.Fake implements _i2.Point<T> {}
-
-class _FakeUIScrollView_1 extends _i1.Fake implements _i3.UIScrollView {}
-
-class _FakeWKPreferences_2 extends _i1.Fake implements _i4.WKPreferences {}
-
-class _FakeWKUserContentController_3 extends _i1.Fake
-    implements _i4.WKUserContentController {}
-
-class _FakeWKHttpCookieStore_4 extends _i1.Fake
-    implements _i4.WKHttpCookieStore {}
-
-class _FakeWKWebsiteDataStore_5 extends _i1.Fake
-    implements _i4.WKWebsiteDataStore {}
-
-class _FakeWKWebViewConfiguration_6 extends _i1.Fake
-    implements _i4.WKWebViewConfiguration {}
-
-class _FakeWKWebView_7 extends _i1.Fake implements _i4.WKWebView {}
-
-/// A class which mocks [UIScrollView].
-///
-/// See the documentation for Mockito's code generation for more information.
-// ignore: must_be_immutable
-class MockUIScrollView extends _i1.Mock implements _i3.UIScrollView {
-  MockUIScrollView() {
-    _i1.throwOnMissingStub(this);
-  }
-
-  @override
-  _i5.Future<_i2.Point<double>> getContentOffset() => (super.noSuchMethod(
-          Invocation.method(#getContentOffset, []),
-          returnValue: Future<_i2.Point<double>>.value(_FakePoint_0<double>()))
-      as _i5.Future<_i2.Point<double>>);
-  @override
-  _i5.Future<void> scrollBy(_i2.Point<double>? offset) =>
-      (super.noSuchMethod(Invocation.method(#scrollBy, [offset]),
-          returnValue: Future<void>.value(),
-          returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
-  @override
-  _i5.Future<void> setContentOffset(_i2.Point<double>? offset) =>
-      (super.noSuchMethod(Invocation.method(#setContentOffset, [offset]),
-          returnValue: Future<void>.value(),
-          returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
-  @override
-  _i3.UIScrollView copy() => (super.noSuchMethod(Invocation.method(#copy, []),
-      returnValue: _FakeUIScrollView_1()) as _i3.UIScrollView);
-  @override
-  _i5.Future<void> setBackgroundColor(_i6.Color? color) =>
-      (super.noSuchMethod(Invocation.method(#setBackgroundColor, [color]),
-          returnValue: Future<void>.value(),
-          returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
-  @override
-  _i5.Future<void> setOpaque(bool? opaque) =>
-      (super.noSuchMethod(Invocation.method(#setOpaque, [opaque]),
-          returnValue: Future<void>.value(),
-          returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
-  @override
-  _i5.Future<void> addObserver(_i7.NSObject? observer,
-          {String? keyPath, Set<_i7.NSKeyValueObservingOptions>? options}) =>
-      (super.noSuchMethod(
-          Invocation.method(
-              #addObserver, [observer], {#keyPath: keyPath, #options: options}),
-          returnValue: Future<void>.value(),
-          returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
-  @override
-  _i5.Future<void> removeObserver(_i7.NSObject? observer, {String? keyPath}) =>
-      (super.noSuchMethod(
-          Invocation.method(#removeObserver, [observer], {#keyPath: keyPath}),
-          returnValue: Future<void>.value(),
-          returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
-}
-
-/// A class which mocks [WKPreferences].
-///
-/// See the documentation for Mockito's code generation for more information.
-// ignore: must_be_immutable
-class MockWKPreferences extends _i1.Mock implements _i4.WKPreferences {
-  MockWKPreferences() {
-    _i1.throwOnMissingStub(this);
-  }
-
-  @override
-  _i5.Future<void> setJavaScriptEnabled(bool? enabled) =>
-      (super.noSuchMethod(Invocation.method(#setJavaScriptEnabled, [enabled]),
-          returnValue: Future<void>.value(),
-          returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
-  @override
-  _i4.WKPreferences copy() => (super.noSuchMethod(Invocation.method(#copy, []),
-      returnValue: _FakeWKPreferences_2()) as _i4.WKPreferences);
-  @override
-  _i5.Future<void> addObserver(_i7.NSObject? observer,
-          {String? keyPath, Set<_i7.NSKeyValueObservingOptions>? options}) =>
-      (super.noSuchMethod(
-          Invocation.method(
-              #addObserver, [observer], {#keyPath: keyPath, #options: options}),
-          returnValue: Future<void>.value(),
-          returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
-  @override
-  _i5.Future<void> removeObserver(_i7.NSObject? observer, {String? keyPath}) =>
-      (super.noSuchMethod(
-          Invocation.method(#removeObserver, [observer], {#keyPath: keyPath}),
-          returnValue: Future<void>.value(),
-          returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
-}
-
-/// A class which mocks [WKUserContentController].
-///
-/// See the documentation for Mockito's code generation for more information.
-// ignore: must_be_immutable
-class MockWKUserContentController extends _i1.Mock
-    implements _i4.WKUserContentController {
-  MockWKUserContentController() {
-    _i1.throwOnMissingStub(this);
-  }
-
-  @override
-  _i5.Future<void> addScriptMessageHandler(
-          _i4.WKScriptMessageHandler? handler, String? name) =>
-      (super.noSuchMethod(
-          Invocation.method(#addScriptMessageHandler, [handler, name]),
-          returnValue: Future<void>.value(),
-          returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
-  @override
-  _i5.Future<void> removeScriptMessageHandler(String? name) => (super
-      .noSuchMethod(Invocation.method(#removeScriptMessageHandler, [name]),
-          returnValue: Future<void>.value(),
-          returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
-  @override
-  _i5.Future<void> removeAllScriptMessageHandlers() => (super.noSuchMethod(
-      Invocation.method(#removeAllScriptMessageHandlers, []),
-      returnValue: Future<void>.value(),
-      returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
-  @override
-  _i5.Future<void> addUserScript(_i4.WKUserScript? userScript) =>
-      (super.noSuchMethod(Invocation.method(#addUserScript, [userScript]),
-          returnValue: Future<void>.value(),
-          returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
-  @override
-  _i5.Future<void> removeAllUserScripts() =>
-      (super.noSuchMethod(Invocation.method(#removeAllUserScripts, []),
-          returnValue: Future<void>.value(),
-          returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
-  @override
-  _i4.WKUserContentController copy() =>
-      (super.noSuchMethod(Invocation.method(#copy, []),
-              returnValue: _FakeWKUserContentController_3())
-          as _i4.WKUserContentController);
-  @override
-  _i5.Future<void> addObserver(_i7.NSObject? observer,
-          {String? keyPath, Set<_i7.NSKeyValueObservingOptions>? options}) =>
-      (super.noSuchMethod(
-          Invocation.method(
-              #addObserver, [observer], {#keyPath: keyPath, #options: options}),
-          returnValue: Future<void>.value(),
-          returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
-  @override
-  _i5.Future<void> removeObserver(_i7.NSObject? observer, {String? keyPath}) =>
-      (super.noSuchMethod(
-          Invocation.method(#removeObserver, [observer], {#keyPath: keyPath}),
-          returnValue: Future<void>.value(),
-          returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
-}
-
-/// A class which mocks [WKWebsiteDataStore].
-///
-/// See the documentation for Mockito's code generation for more information.
-// ignore: must_be_immutable
-class MockWKWebsiteDataStore extends _i1.Mock
-    implements _i4.WKWebsiteDataStore {
-  MockWKWebsiteDataStore() {
-    _i1.throwOnMissingStub(this);
-  }
-
-  @override
-  _i4.WKHttpCookieStore get httpCookieStore =>
-      (super.noSuchMethod(Invocation.getter(#httpCookieStore),
-          returnValue: _FakeWKHttpCookieStore_4()) as _i4.WKHttpCookieStore);
-  @override
-  _i5.Future<bool> removeDataOfTypes(
-          Set<_i4.WKWebsiteDataType>? dataTypes, DateTime? since) =>
-      (super.noSuchMethod(
-          Invocation.method(#removeDataOfTypes, [dataTypes, since]),
-          returnValue: Future<bool>.value(false)) as _i5.Future<bool>);
-  @override
-  _i4.WKWebsiteDataStore copy() =>
-      (super.noSuchMethod(Invocation.method(#copy, []),
-          returnValue: _FakeWKWebsiteDataStore_5()) as _i4.WKWebsiteDataStore);
-  @override
-  _i5.Future<void> addObserver(_i7.NSObject? observer,
-          {String? keyPath, Set<_i7.NSKeyValueObservingOptions>? options}) =>
-      (super.noSuchMethod(
-          Invocation.method(
-              #addObserver, [observer], {#keyPath: keyPath, #options: options}),
-          returnValue: Future<void>.value(),
-          returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
-  @override
-  _i5.Future<void> removeObserver(_i7.NSObject? observer, {String? keyPath}) =>
-      (super.noSuchMethod(
-          Invocation.method(#removeObserver, [observer], {#keyPath: keyPath}),
-          returnValue: Future<void>.value(),
-          returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
-}
-
-/// A class which mocks [WKWebView].
-///
-/// See the documentation for Mockito's code generation for more information.
-// ignore: must_be_immutable
-class MockWKWebView extends _i1.Mock implements _i4.WKWebView {
-  MockWKWebView() {
-    _i1.throwOnMissingStub(this);
-  }
-
-  @override
-  _i4.WKWebViewConfiguration get configuration =>
-      (super.noSuchMethod(Invocation.getter(#configuration),
-              returnValue: _FakeWKWebViewConfiguration_6())
-          as _i4.WKWebViewConfiguration);
-  @override
-  _i3.UIScrollView get scrollView =>
-      (super.noSuchMethod(Invocation.getter(#scrollView),
-          returnValue: _FakeUIScrollView_1()) as _i3.UIScrollView);
-  @override
-  _i5.Future<void> setUIDelegate(_i4.WKUIDelegate? delegate) =>
-      (super.noSuchMethod(Invocation.method(#setUIDelegate, [delegate]),
-          returnValue: Future<void>.value(),
-          returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
-  @override
-  _i5.Future<void> setNavigationDelegate(_i4.WKNavigationDelegate? delegate) =>
-      (super.noSuchMethod(Invocation.method(#setNavigationDelegate, [delegate]),
-          returnValue: Future<void>.value(),
-          returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
-  @override
-  _i5.Future<String?> getUrl() =>
-      (super.noSuchMethod(Invocation.method(#getUrl, []),
-          returnValue: Future<String?>.value()) as _i5.Future<String?>);
-  @override
-  _i5.Future<double> getEstimatedProgress() =>
-      (super.noSuchMethod(Invocation.method(#getEstimatedProgress, []),
-          returnValue: Future<double>.value(0.0)) as _i5.Future<double>);
-  @override
-  _i5.Future<void> loadRequest(_i7.NSUrlRequest? request) =>
-      (super.noSuchMethod(Invocation.method(#loadRequest, [request]),
-          returnValue: Future<void>.value(),
-          returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
-  @override
-  _i5.Future<void> loadHtmlString(String? string, {String? baseUrl}) =>
-      (super.noSuchMethod(
-          Invocation.method(#loadHtmlString, [string], {#baseUrl: baseUrl}),
-          returnValue: Future<void>.value(),
-          returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
-  @override
-  _i5.Future<void> loadFileUrl(String? url, {String? readAccessUrl}) =>
-      (super.noSuchMethod(
-          Invocation.method(
-              #loadFileUrl, [url], {#readAccessUrl: readAccessUrl}),
-          returnValue: Future<void>.value(),
-          returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
-  @override
-  _i5.Future<void> loadFlutterAsset(String? key) =>
-      (super.noSuchMethod(Invocation.method(#loadFlutterAsset, [key]),
-          returnValue: Future<void>.value(),
-          returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
-  @override
-  _i5.Future<bool> canGoBack() =>
-      (super.noSuchMethod(Invocation.method(#canGoBack, []),
-          returnValue: Future<bool>.value(false)) as _i5.Future<bool>);
-  @override
-  _i5.Future<bool> canGoForward() =>
-      (super.noSuchMethod(Invocation.method(#canGoForward, []),
-          returnValue: Future<bool>.value(false)) as _i5.Future<bool>);
-  @override
-  _i5.Future<void> goBack() =>
-      (super.noSuchMethod(Invocation.method(#goBack, []),
-          returnValue: Future<void>.value(),
-          returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
-  @override
-  _i5.Future<void> goForward() =>
-      (super.noSuchMethod(Invocation.method(#goForward, []),
-          returnValue: Future<void>.value(),
-          returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
-  @override
-  _i5.Future<void> reload() =>
-      (super.noSuchMethod(Invocation.method(#reload, []),
-          returnValue: Future<void>.value(),
-          returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
-  @override
-  _i5.Future<String?> getTitle() =>
-      (super.noSuchMethod(Invocation.method(#getTitle, []),
-          returnValue: Future<String?>.value()) as _i5.Future<String?>);
-  @override
-  _i5.Future<void> setAllowsBackForwardNavigationGestures(bool? allow) =>
-      (super.noSuchMethod(
-          Invocation.method(#setAllowsBackForwardNavigationGestures, [allow]),
-          returnValue: Future<void>.value(),
-          returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
-  @override
-  _i5.Future<void> setCustomUserAgent(String? userAgent) =>
-      (super.noSuchMethod(Invocation.method(#setCustomUserAgent, [userAgent]),
-          returnValue: Future<void>.value(),
-          returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
-  @override
-  _i5.Future<Object?> evaluateJavaScript(String? javaScriptString) => (super
-      .noSuchMethod(Invocation.method(#evaluateJavaScript, [javaScriptString]),
-          returnValue: Future<Object?>.value()) as _i5.Future<Object?>);
-  @override
-  _i4.WKWebView copy() => (super.noSuchMethod(Invocation.method(#copy, []),
-      returnValue: _FakeWKWebView_7()) as _i4.WKWebView);
-  @override
-  _i5.Future<void> setBackgroundColor(_i6.Color? color) =>
-      (super.noSuchMethod(Invocation.method(#setBackgroundColor, [color]),
-          returnValue: Future<void>.value(),
-          returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
-  @override
-  _i5.Future<void> setOpaque(bool? opaque) =>
-      (super.noSuchMethod(Invocation.method(#setOpaque, [opaque]),
-          returnValue: Future<void>.value(),
-          returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
-  @override
-  _i5.Future<void> addObserver(_i7.NSObject? observer,
-          {String? keyPath, Set<_i7.NSKeyValueObservingOptions>? options}) =>
-      (super.noSuchMethod(
-          Invocation.method(
-              #addObserver, [observer], {#keyPath: keyPath, #options: options}),
-          returnValue: Future<void>.value(),
-          returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
-  @override
-  _i5.Future<void> removeObserver(_i7.NSObject? observer, {String? keyPath}) =>
-      (super.noSuchMethod(
-          Invocation.method(#removeObserver, [observer], {#keyPath: keyPath}),
-          returnValue: Future<void>.value(),
-          returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
-}
-
-/// A class which mocks [WKWebViewConfiguration].
-///
-/// See the documentation for Mockito's code generation for more information.
-// ignore: must_be_immutable
-class MockWKWebViewConfiguration extends _i1.Mock
-    implements _i4.WKWebViewConfiguration {
-  MockWKWebViewConfiguration() {
-    _i1.throwOnMissingStub(this);
-  }
-
-  @override
-  _i4.WKUserContentController get userContentController =>
-      (super.noSuchMethod(Invocation.getter(#userContentController),
-              returnValue: _FakeWKUserContentController_3())
-          as _i4.WKUserContentController);
-  @override
-  _i4.WKPreferences get preferences =>
-      (super.noSuchMethod(Invocation.getter(#preferences),
-          returnValue: _FakeWKPreferences_2()) as _i4.WKPreferences);
-  @override
-  _i4.WKWebsiteDataStore get websiteDataStore =>
-      (super.noSuchMethod(Invocation.getter(#websiteDataStore),
-          returnValue: _FakeWKWebsiteDataStore_5()) as _i4.WKWebsiteDataStore);
-  @override
-  _i5.Future<void> setAllowsInlineMediaPlayback(bool? allow) => (super
-      .noSuchMethod(Invocation.method(#setAllowsInlineMediaPlayback, [allow]),
-          returnValue: Future<void>.value(),
-          returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
-  @override
-  _i5.Future<void> setMediaTypesRequiringUserActionForPlayback(
-          Set<_i4.WKAudiovisualMediaType>? types) =>
-      (super.noSuchMethod(
-          Invocation.method(
-              #setMediaTypesRequiringUserActionForPlayback, [types]),
-          returnValue: Future<void>.value(),
-          returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
-  @override
-  _i4.WKWebViewConfiguration copy() =>
-      (super.noSuchMethod(Invocation.method(#copy, []),
-              returnValue: _FakeWKWebViewConfiguration_6())
-          as _i4.WKWebViewConfiguration);
-  @override
-  _i5.Future<void> addObserver(_i7.NSObject? observer,
-          {String? keyPath, Set<_i7.NSKeyValueObservingOptions>? options}) =>
-      (super.noSuchMethod(
-          Invocation.method(
-              #addObserver, [observer], {#keyPath: keyPath, #options: options}),
-          returnValue: Future<void>.value(),
-          returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
-  @override
-  _i5.Future<void> removeObserver(_i7.NSObject? observer, {String? keyPath}) =>
-      (super.noSuchMethod(
-          Invocation.method(#removeObserver, [observer], {#keyPath: keyPath}),
-          returnValue: Future<void>.value(),
-          returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
-}
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/test/v4/webkit_webview_cookie_manager_test.mocks.dart b/packages/webview_flutter/webview_flutter_wkwebview/test/v4/webkit_webview_cookie_manager_test.mocks.dart
deleted file mode 100644
index 90bf252..0000000
--- a/packages/webview_flutter/webview_flutter_wkwebview/test/v4/webkit_webview_cookie_manager_test.mocks.dart
+++ /dev/null
@@ -1,100 +0,0 @@
-// Mocks generated by Mockito 5.2.0 from annotations
-// in webview_flutter_wkwebview/test/v4/webkit_webview_cookie_manager_test.dart.
-// Do not manually edit this file.
-
-import 'dart:async' as _i3;
-
-import 'package:mockito/mockito.dart' as _i1;
-import 'package:webview_flutter_wkwebview/src/foundation/foundation.dart'
-    as _i4;
-import 'package:webview_flutter_wkwebview/src/web_kit/web_kit.dart' as _i2;
-
-// ignore_for_file: type=lint
-// ignore_for_file: avoid_redundant_argument_values
-// ignore_for_file: avoid_setters_without_getters
-// ignore_for_file: comment_references
-// ignore_for_file: implementation_imports
-// ignore_for_file: invalid_use_of_visible_for_testing_member
-// ignore_for_file: prefer_const_constructors
-// ignore_for_file: unnecessary_parenthesis
-// ignore_for_file: camel_case_types
-
-class _FakeWKHttpCookieStore_0 extends _i1.Fake
-    implements _i2.WKHttpCookieStore {}
-
-class _FakeWKWebsiteDataStore_1 extends _i1.Fake
-    implements _i2.WKWebsiteDataStore {}
-
-/// A class which mocks [WKWebsiteDataStore].
-///
-/// See the documentation for Mockito's code generation for more information.
-// ignore: must_be_immutable
-class MockWKWebsiteDataStore extends _i1.Mock
-    implements _i2.WKWebsiteDataStore {
-  MockWKWebsiteDataStore() {
-    _i1.throwOnMissingStub(this);
-  }
-
-  @override
-  _i2.WKHttpCookieStore get httpCookieStore =>
-      (super.noSuchMethod(Invocation.getter(#httpCookieStore),
-          returnValue: _FakeWKHttpCookieStore_0()) as _i2.WKHttpCookieStore);
-  @override
-  _i3.Future<bool> removeDataOfTypes(
-          Set<_i2.WKWebsiteDataType>? dataTypes, DateTime? since) =>
-      (super.noSuchMethod(
-          Invocation.method(#removeDataOfTypes, [dataTypes, since]),
-          returnValue: Future<bool>.value(false)) as _i3.Future<bool>);
-  @override
-  _i2.WKWebsiteDataStore copy() =>
-      (super.noSuchMethod(Invocation.method(#copy, []),
-          returnValue: _FakeWKWebsiteDataStore_1()) as _i2.WKWebsiteDataStore);
-  @override
-  _i3.Future<void> addObserver(_i4.NSObject? observer,
-          {String? keyPath, Set<_i4.NSKeyValueObservingOptions>? options}) =>
-      (super.noSuchMethod(
-          Invocation.method(
-              #addObserver, [observer], {#keyPath: keyPath, #options: options}),
-          returnValue: Future<void>.value(),
-          returnValueForMissingStub: Future<void>.value()) as _i3.Future<void>);
-  @override
-  _i3.Future<void> removeObserver(_i4.NSObject? observer, {String? keyPath}) =>
-      (super.noSuchMethod(
-          Invocation.method(#removeObserver, [observer], {#keyPath: keyPath}),
-          returnValue: Future<void>.value(),
-          returnValueForMissingStub: Future<void>.value()) as _i3.Future<void>);
-}
-
-/// A class which mocks [WKHttpCookieStore].
-///
-/// See the documentation for Mockito's code generation for more information.
-// ignore: must_be_immutable
-class MockWKHttpCookieStore extends _i1.Mock implements _i2.WKHttpCookieStore {
-  MockWKHttpCookieStore() {
-    _i1.throwOnMissingStub(this);
-  }
-
-  @override
-  _i3.Future<void> setCookie(_i4.NSHttpCookie? cookie) =>
-      (super.noSuchMethod(Invocation.method(#setCookie, [cookie]),
-          returnValue: Future<void>.value(),
-          returnValueForMissingStub: Future<void>.value()) as _i3.Future<void>);
-  @override
-  _i2.WKHttpCookieStore copy() =>
-      (super.noSuchMethod(Invocation.method(#copy, []),
-          returnValue: _FakeWKHttpCookieStore_0()) as _i2.WKHttpCookieStore);
-  @override
-  _i3.Future<void> addObserver(_i4.NSObject? observer,
-          {String? keyPath, Set<_i4.NSKeyValueObservingOptions>? options}) =>
-      (super.noSuchMethod(
-          Invocation.method(
-              #addObserver, [observer], {#keyPath: keyPath, #options: options}),
-          returnValue: Future<void>.value(),
-          returnValueForMissingStub: Future<void>.value()) as _i3.Future<void>);
-  @override
-  _i3.Future<void> removeObserver(_i4.NSObject? observer, {String? keyPath}) =>
-      (super.noSuchMethod(
-          Invocation.method(#removeObserver, [observer], {#keyPath: keyPath}),
-          returnValue: Future<void>.value(),
-          returnValueForMissingStub: Future<void>.value()) as _i3.Future<void>);
-}
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/test/v4/webkit_navigation_delegate_test.dart b/packages/webview_flutter/webview_flutter_wkwebview/test/webkit_navigation_delegate_test.dart
similarity index 70%
rename from packages/webview_flutter/webview_flutter_wkwebview/test/v4/webkit_navigation_delegate_test.dart
rename to packages/webview_flutter/webview_flutter_wkwebview/test/webkit_navigation_delegate_test.dart
index fe57e94..731819f 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/test/v4/webkit_navigation_delegate_test.dart
+++ b/packages/webview_flutter/webview_flutter_wkwebview/test/webkit_navigation_delegate_test.dart
@@ -6,21 +6,38 @@
 
 import 'package:flutter/material.dart';
 import 'package:flutter_test/flutter_test.dart';
-import 'package:webview_flutter_platform_interface/v4/webview_flutter_platform_interface.dart';
+import 'package:mockito/annotations.dart';
+import 'package:mockito/mockito.dart';
+import 'package:webview_flutter_platform_interface/webview_flutter_platform_interface.dart';
 import 'package:webview_flutter_wkwebview/src/foundation/foundation.dart';
-import 'package:webview_flutter_wkwebview/src/v4/src/webkit_proxy.dart';
-import 'package:webview_flutter_wkwebview/src/v4/webview_flutter_wkwebview.dart';
 import 'package:webview_flutter_wkwebview/src/web_kit/web_kit.dart';
+import 'package:webview_flutter_wkwebview/src/webkit_proxy.dart';
+import 'package:webview_flutter_wkwebview/webview_flutter_wkwebview.dart';
 
+import 'webkit_navigation_delegate_test.mocks.dart';
+
+@GenerateMocks(<Type>[WKWebView])
 void main() {
   WidgetsFlutterBinding.ensureInitialized();
 
   group('WebKitNavigationDelegate', () {
+    test('WebKitNavigationDelegate uses params field in constructor', () async {
+      await runZonedGuarded(
+        () async => WebKitNavigationDelegate(
+          const PlatformNavigationDelegateCreationParams(),
+        ),
+        (Object error, __) {
+          expect(error, isNot(isA<TypeError>()));
+        },
+      );
+    });
+
     test('setOnPageFinished', () {
       final WebKitNavigationDelegate webKitDelgate = WebKitNavigationDelegate(
         const WebKitNavigationDelegateCreationParams(
           webKitProxy: WebKitProxy(
             createNavigationDelegate: CapturingNavigationDelegate.new,
+            createUIDelegate: CapturingUIDelegate.new,
           ),
         ),
       );
@@ -41,6 +58,7 @@
         const WebKitNavigationDelegateCreationParams(
           webKitProxy: WebKitProxy(
             createNavigationDelegate: CapturingNavigationDelegate.new,
+            createUIDelegate: CapturingUIDelegate.new,
           ),
         ),
       );
@@ -62,6 +80,7 @@
         const WebKitNavigationDelegateCreationParams(
           webKitProxy: WebKitProxy(
             createNavigationDelegate: CapturingNavigationDelegate.new,
+            createUIDelegate: CapturingUIDelegate.new,
           ),
         ),
       );
@@ -86,6 +105,7 @@
       expect(callbackError.errorCode, WKErrorCode.webViewInvalidated);
       expect(callbackError.domain, 'domain');
       expect(callbackError.errorType, WebResourceErrorType.webViewInvalidated);
+      expect(callbackError.isForMainFrame, true);
     });
 
     test('onWebResourceError from didFailProvisionalNavigation', () {
@@ -93,6 +113,7 @@
         const WebKitNavigationDelegateCreationParams(
           webKitProxy: WebKitProxy(
             createNavigationDelegate: CapturingNavigationDelegate.new,
+            createUIDelegate: CapturingUIDelegate.new,
           ),
         ),
       );
@@ -118,6 +139,7 @@
       expect(callbackError.errorCode, WKErrorCode.webViewInvalidated);
       expect(callbackError.domain, 'domain');
       expect(callbackError.errorType, WebResourceErrorType.webViewInvalidated);
+      expect(callbackError.isForMainFrame, true);
     });
 
     test('onWebResourceError from webViewWebContentProcessDidTerminate', () {
@@ -125,6 +147,7 @@
         const WebKitNavigationDelegateCreationParams(
           webKitProxy: WebKitProxy(
             createNavigationDelegate: CapturingNavigationDelegate.new,
+            createUIDelegate: CapturingUIDelegate.new,
           ),
         ),
       );
@@ -148,6 +171,7 @@
         callbackError.errorType,
         WebResourceErrorType.webContentProcessTerminated,
       );
+      expect(callbackError.isForMainFrame, true);
     });
 
     test('onNavigationRequest from decidePolicyForNavigationAction', () {
@@ -155,19 +179,16 @@
         const WebKitNavigationDelegateCreationParams(
           webKitProxy: WebKitProxy(
             createNavigationDelegate: CapturingNavigationDelegate.new,
+            createUIDelegate: CapturingUIDelegate.new,
           ),
         ),
       );
 
-      late final String callbackUrl;
-      late final bool callbackIsMainFrame;
-      FutureOr<bool> onNavigationRequest({
-        required String url,
-        required bool isForMainFrame,
-      }) {
-        callbackUrl = url;
-        callbackIsMainFrame = isForMainFrame;
-        return true;
+      late final NavigationRequest callbackRequest;
+      FutureOr<NavigationDecision> onNavigationRequest(
+          NavigationRequest request) {
+        callbackRequest = request;
+        return NavigationDecision.navigate;
       }
 
       webKitDelgate.setOnNavigationRequest(onNavigationRequest);
@@ -184,8 +205,34 @@
         completion(WKNavigationActionPolicy.allow),
       );
 
-      expect(callbackUrl, 'https://www.google.com');
-      expect(callbackIsMainFrame, isFalse);
+      expect(callbackRequest.url, 'https://www.google.com');
+      expect(callbackRequest.isMainFrame, isFalse);
+    });
+
+    test('Requests to open a new window loads request in same window', () {
+      WebKitNavigationDelegate(
+        const WebKitNavigationDelegateCreationParams(
+          webKitProxy: WebKitProxy(
+            createNavigationDelegate: CapturingNavigationDelegate.new,
+            createUIDelegate: CapturingUIDelegate.new,
+          ),
+        ),
+      );
+
+      final MockWKWebView mockWebView = MockWKWebView();
+
+      const NSUrlRequest request = NSUrlRequest(url: 'https://www.google.com');
+
+      CapturingUIDelegate.lastCreatedDelegate.onCreateWebView!(
+        mockWebView,
+        WKWebViewConfiguration.detached(),
+        const WKNavigationAction(
+          request: request,
+          targetFrame: WKFrameInfo(isMainFrame: false),
+        ),
+      );
+
+      verify(mockWebView.loadRequest(request));
     });
   });
 }
@@ -205,3 +252,11 @@
   static CapturingNavigationDelegate lastCreatedDelegate =
       CapturingNavigationDelegate();
 }
+
+// Records the last created instance of itself.
+class CapturingUIDelegate extends WKUIDelegate {
+  CapturingUIDelegate({super.onCreateWebView}) : super.detached() {
+    lastCreatedDelegate = this;
+  }
+  static CapturingUIDelegate lastCreatedDelegate = CapturingUIDelegate();
+}
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/test/webkit_navigation_delegate_test.mocks.dart b/packages/webview_flutter/webview_flutter_wkwebview/test/webkit_navigation_delegate_test.mocks.dart
new file mode 100644
index 0000000..9eab6dd
--- /dev/null
+++ b/packages/webview_flutter/webview_flutter_wkwebview/test/webkit_navigation_delegate_test.mocks.dart
@@ -0,0 +1,308 @@
+// Mocks generated by Mockito 5.3.2 from annotations
+// in webview_flutter_wkwebview/test/webkit_navigation_delegate_test.dart.
+// Do not manually edit this file.
+
+// ignore_for_file: no_leading_underscores_for_library_prefixes
+import 'dart:async' as _i4;
+import 'dart:ui' as _i6;
+
+import 'package:mockito/mockito.dart' as _i1;
+import 'package:webview_flutter_wkwebview/src/foundation/foundation.dart'
+    as _i5;
+import 'package:webview_flutter_wkwebview/src/ui_kit/ui_kit.dart' as _i3;
+import 'package:webview_flutter_wkwebview/src/web_kit/web_kit.dart' as _i2;
+
+// ignore_for_file: type=lint
+// ignore_for_file: avoid_redundant_argument_values
+// ignore_for_file: avoid_setters_without_getters
+// ignore_for_file: comment_references
+// ignore_for_file: implementation_imports
+// ignore_for_file: invalid_use_of_visible_for_testing_member
+// ignore_for_file: prefer_const_constructors
+// ignore_for_file: unnecessary_parenthesis
+// ignore_for_file: camel_case_types
+// ignore_for_file: subtype_of_sealed_class
+
+class _FakeWKWebViewConfiguration_0 extends _i1.SmartFake
+    implements _i2.WKWebViewConfiguration {
+  _FakeWKWebViewConfiguration_0(
+    Object parent,
+    Invocation parentInvocation,
+  ) : super(
+          parent,
+          parentInvocation,
+        );
+}
+
+class _FakeUIScrollView_1 extends _i1.SmartFake implements _i3.UIScrollView {
+  _FakeUIScrollView_1(
+    Object parent,
+    Invocation parentInvocation,
+  ) : super(
+          parent,
+          parentInvocation,
+        );
+}
+
+class _FakeWKWebView_2 extends _i1.SmartFake implements _i2.WKWebView {
+  _FakeWKWebView_2(
+    Object parent,
+    Invocation parentInvocation,
+  ) : super(
+          parent,
+          parentInvocation,
+        );
+}
+
+/// A class which mocks [WKWebView].
+///
+/// See the documentation for Mockito's code generation for more information.
+// ignore: must_be_immutable
+class MockWKWebView extends _i1.Mock implements _i2.WKWebView {
+  MockWKWebView() {
+    _i1.throwOnMissingStub(this);
+  }
+
+  @override
+  _i2.WKWebViewConfiguration get configuration => (super.noSuchMethod(
+        Invocation.getter(#configuration),
+        returnValue: _FakeWKWebViewConfiguration_0(
+          this,
+          Invocation.getter(#configuration),
+        ),
+      ) as _i2.WKWebViewConfiguration);
+  @override
+  _i3.UIScrollView get scrollView => (super.noSuchMethod(
+        Invocation.getter(#scrollView),
+        returnValue: _FakeUIScrollView_1(
+          this,
+          Invocation.getter(#scrollView),
+        ),
+      ) as _i3.UIScrollView);
+  @override
+  _i4.Future<void> setUIDelegate(_i2.WKUIDelegate? delegate) =>
+      (super.noSuchMethod(
+        Invocation.method(
+          #setUIDelegate,
+          [delegate],
+        ),
+        returnValue: _i4.Future<void>.value(),
+        returnValueForMissingStub: _i4.Future<void>.value(),
+      ) as _i4.Future<void>);
+  @override
+  _i4.Future<void> setNavigationDelegate(_i2.WKNavigationDelegate? delegate) =>
+      (super.noSuchMethod(
+        Invocation.method(
+          #setNavigationDelegate,
+          [delegate],
+        ),
+        returnValue: _i4.Future<void>.value(),
+        returnValueForMissingStub: _i4.Future<void>.value(),
+      ) as _i4.Future<void>);
+  @override
+  _i4.Future<String?> getUrl() => (super.noSuchMethod(
+        Invocation.method(
+          #getUrl,
+          [],
+        ),
+        returnValue: _i4.Future<String?>.value(),
+      ) as _i4.Future<String?>);
+  @override
+  _i4.Future<double> getEstimatedProgress() => (super.noSuchMethod(
+        Invocation.method(
+          #getEstimatedProgress,
+          [],
+        ),
+        returnValue: _i4.Future<double>.value(0.0),
+      ) as _i4.Future<double>);
+  @override
+  _i4.Future<void> loadRequest(_i5.NSUrlRequest? request) =>
+      (super.noSuchMethod(
+        Invocation.method(
+          #loadRequest,
+          [request],
+        ),
+        returnValue: _i4.Future<void>.value(),
+        returnValueForMissingStub: _i4.Future<void>.value(),
+      ) as _i4.Future<void>);
+  @override
+  _i4.Future<void> loadHtmlString(
+    String? string, {
+    String? baseUrl,
+  }) =>
+      (super.noSuchMethod(
+        Invocation.method(
+          #loadHtmlString,
+          [string],
+          {#baseUrl: baseUrl},
+        ),
+        returnValue: _i4.Future<void>.value(),
+        returnValueForMissingStub: _i4.Future<void>.value(),
+      ) as _i4.Future<void>);
+  @override
+  _i4.Future<void> loadFileUrl(
+    String? url, {
+    required String? readAccessUrl,
+  }) =>
+      (super.noSuchMethod(
+        Invocation.method(
+          #loadFileUrl,
+          [url],
+          {#readAccessUrl: readAccessUrl},
+        ),
+        returnValue: _i4.Future<void>.value(),
+        returnValueForMissingStub: _i4.Future<void>.value(),
+      ) as _i4.Future<void>);
+  @override
+  _i4.Future<void> loadFlutterAsset(String? key) => (super.noSuchMethod(
+        Invocation.method(
+          #loadFlutterAsset,
+          [key],
+        ),
+        returnValue: _i4.Future<void>.value(),
+        returnValueForMissingStub: _i4.Future<void>.value(),
+      ) as _i4.Future<void>);
+  @override
+  _i4.Future<bool> canGoBack() => (super.noSuchMethod(
+        Invocation.method(
+          #canGoBack,
+          [],
+        ),
+        returnValue: _i4.Future<bool>.value(false),
+      ) as _i4.Future<bool>);
+  @override
+  _i4.Future<bool> canGoForward() => (super.noSuchMethod(
+        Invocation.method(
+          #canGoForward,
+          [],
+        ),
+        returnValue: _i4.Future<bool>.value(false),
+      ) as _i4.Future<bool>);
+  @override
+  _i4.Future<void> goBack() => (super.noSuchMethod(
+        Invocation.method(
+          #goBack,
+          [],
+        ),
+        returnValue: _i4.Future<void>.value(),
+        returnValueForMissingStub: _i4.Future<void>.value(),
+      ) as _i4.Future<void>);
+  @override
+  _i4.Future<void> goForward() => (super.noSuchMethod(
+        Invocation.method(
+          #goForward,
+          [],
+        ),
+        returnValue: _i4.Future<void>.value(),
+        returnValueForMissingStub: _i4.Future<void>.value(),
+      ) as _i4.Future<void>);
+  @override
+  _i4.Future<void> reload() => (super.noSuchMethod(
+        Invocation.method(
+          #reload,
+          [],
+        ),
+        returnValue: _i4.Future<void>.value(),
+        returnValueForMissingStub: _i4.Future<void>.value(),
+      ) as _i4.Future<void>);
+  @override
+  _i4.Future<String?> getTitle() => (super.noSuchMethod(
+        Invocation.method(
+          #getTitle,
+          [],
+        ),
+        returnValue: _i4.Future<String?>.value(),
+      ) as _i4.Future<String?>);
+  @override
+  _i4.Future<void> setAllowsBackForwardNavigationGestures(bool? allow) =>
+      (super.noSuchMethod(
+        Invocation.method(
+          #setAllowsBackForwardNavigationGestures,
+          [allow],
+        ),
+        returnValue: _i4.Future<void>.value(),
+        returnValueForMissingStub: _i4.Future<void>.value(),
+      ) as _i4.Future<void>);
+  @override
+  _i4.Future<void> setCustomUserAgent(String? userAgent) => (super.noSuchMethod(
+        Invocation.method(
+          #setCustomUserAgent,
+          [userAgent],
+        ),
+        returnValue: _i4.Future<void>.value(),
+        returnValueForMissingStub: _i4.Future<void>.value(),
+      ) as _i4.Future<void>);
+  @override
+  _i4.Future<Object?> evaluateJavaScript(String? javaScriptString) =>
+      (super.noSuchMethod(
+        Invocation.method(
+          #evaluateJavaScript,
+          [javaScriptString],
+        ),
+        returnValue: _i4.Future<Object?>.value(),
+      ) as _i4.Future<Object?>);
+  @override
+  _i2.WKWebView copy() => (super.noSuchMethod(
+        Invocation.method(
+          #copy,
+          [],
+        ),
+        returnValue: _FakeWKWebView_2(
+          this,
+          Invocation.method(
+            #copy,
+            [],
+          ),
+        ),
+      ) as _i2.WKWebView);
+  @override
+  _i4.Future<void> setBackgroundColor(_i6.Color? color) => (super.noSuchMethod(
+        Invocation.method(
+          #setBackgroundColor,
+          [color],
+        ),
+        returnValue: _i4.Future<void>.value(),
+        returnValueForMissingStub: _i4.Future<void>.value(),
+      ) as _i4.Future<void>);
+  @override
+  _i4.Future<void> setOpaque(bool? opaque) => (super.noSuchMethod(
+        Invocation.method(
+          #setOpaque,
+          [opaque],
+        ),
+        returnValue: _i4.Future<void>.value(),
+        returnValueForMissingStub: _i4.Future<void>.value(),
+      ) as _i4.Future<void>);
+  @override
+  _i4.Future<void> addObserver(
+    _i5.NSObject? observer, {
+    required String? keyPath,
+    required Set<_i5.NSKeyValueObservingOptions>? options,
+  }) =>
+      (super.noSuchMethod(
+        Invocation.method(
+          #addObserver,
+          [observer],
+          {
+            #keyPath: keyPath,
+            #options: options,
+          },
+        ),
+        returnValue: _i4.Future<void>.value(),
+        returnValueForMissingStub: _i4.Future<void>.value(),
+      ) as _i4.Future<void>);
+  @override
+  _i4.Future<void> removeObserver(
+    _i5.NSObject? observer, {
+    required String? keyPath,
+  }) =>
+      (super.noSuchMethod(
+        Invocation.method(
+          #removeObserver,
+          [observer],
+          {#keyPath: keyPath},
+        ),
+        returnValue: _i4.Future<void>.value(),
+        returnValueForMissingStub: _i4.Future<void>.value(),
+      ) as _i4.Future<void>);
+}
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/test/v4/webkit_webview_controller_test.dart b/packages/webview_flutter/webview_flutter_wkwebview/test/webkit_webview_controller_test.dart
similarity index 82%
rename from packages/webview_flutter/webview_flutter_wkwebview/test/v4/webkit_webview_controller_test.dart
rename to packages/webview_flutter/webview_flutter_wkwebview/test/webkit_webview_controller_test.dart
index 6672198..fc06db2 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/test/v4/webkit_webview_controller_test.dart
+++ b/packages/webview_flutter/webview_flutter_wkwebview/test/webkit_webview_controller_test.dart
@@ -12,12 +12,12 @@
 import 'package:flutter_test/flutter_test.dart';
 import 'package:mockito/annotations.dart';
 import 'package:mockito/mockito.dart';
-import 'package:webview_flutter_platform_interface/v4/webview_flutter_platform_interface.dart';
+import 'package:webview_flutter_platform_interface/webview_flutter_platform_interface.dart';
 import 'package:webview_flutter_wkwebview/src/foundation/foundation.dart';
 import 'package:webview_flutter_wkwebview/src/ui_kit/ui_kit.dart';
-import 'package:webview_flutter_wkwebview/src/v4/src/webkit_proxy.dart';
-import 'package:webview_flutter_wkwebview/src/v4/webview_flutter_wkwebview.dart';
 import 'package:webview_flutter_wkwebview/src/web_kit/web_kit.dart';
+import 'package:webview_flutter_wkwebview/src/webkit_proxy.dart';
+import 'package:webview_flutter_wkwebview/webview_flutter_wkwebview.dart';
 
 import 'webkit_webview_controller_test.mocks.dart';
 
@@ -97,6 +97,86 @@
       return controller;
     }
 
+    group('WebKitWebViewControllerCreationParams', () {
+      test('allowsInlineMediaPlayback', () {
+        final MockWKWebViewConfiguration mockConfiguration =
+            MockWKWebViewConfiguration();
+
+        WebKitWebViewControllerCreationParams(
+          webKitProxy: WebKitProxy(
+            createWebViewConfiguration: () => mockConfiguration,
+          ),
+          allowsInlineMediaPlayback: true,
+        );
+
+        verify(
+          mockConfiguration.setAllowsInlineMediaPlayback(true),
+        );
+      });
+
+      test('mediaTypesRequiringUserAction', () {
+        final MockWKWebViewConfiguration mockConfiguration =
+            MockWKWebViewConfiguration();
+
+        WebKitWebViewControllerCreationParams(
+          webKitProxy: WebKitProxy(
+            createWebViewConfiguration: () => mockConfiguration,
+          ),
+          mediaTypesRequiringUserAction: const <PlaybackMediaTypes>{
+            PlaybackMediaTypes.video,
+          },
+        );
+
+        verify(
+          mockConfiguration.setMediaTypesRequiringUserActionForPlayback(
+            <WKAudiovisualMediaType>{
+              WKAudiovisualMediaType.video,
+            },
+          ),
+        );
+      });
+
+      test('mediaTypesRequiringUserAction defaults to include audio and video',
+          () {
+        final MockWKWebViewConfiguration mockConfiguration =
+            MockWKWebViewConfiguration();
+
+        WebKitWebViewControllerCreationParams(
+          webKitProxy: WebKitProxy(
+            createWebViewConfiguration: () => mockConfiguration,
+          ),
+        );
+
+        verify(
+          mockConfiguration.setMediaTypesRequiringUserActionForPlayback(
+            <WKAudiovisualMediaType>{
+              WKAudiovisualMediaType.audio,
+              WKAudiovisualMediaType.video,
+            },
+          ),
+        );
+      });
+
+      test('mediaTypesRequiringUserAction sets value to none if set is empty',
+          () {
+        final MockWKWebViewConfiguration mockConfiguration =
+            MockWKWebViewConfiguration();
+
+        WebKitWebViewControllerCreationParams(
+          webKitProxy: WebKitProxy(
+            createWebViewConfiguration: () => mockConfiguration,
+          ),
+          mediaTypesRequiringUserAction: const <PlaybackMediaTypes>{},
+        );
+
+        verify(
+          mockConfiguration.setMediaTypesRequiringUserActionForPlayback(
+            <WKAudiovisualMediaType>{WKAudiovisualMediaType.none},
+          ),
+        );
+      });
+    });
+
     test('loadFile', () async {
       final MockWKWebView mockWebView = MockWKWebView();
 
@@ -148,11 +228,7 @@
 
         expect(
           () async => controller.loadRequest(
-            LoadRequestParams(
-              uri: Uri.parse('www.google.com'),
-              method: LoadRequestMethod.get,
-              headers: const <String, String>{},
-            ),
+            LoadRequestParams(uri: Uri.parse('www.google.com')),
           ),
           throwsA(isA<ArgumentError>()),
         );
@@ -166,11 +242,7 @@
         );
 
         await controller.loadRequest(
-          LoadRequestParams(
-            uri: Uri.parse('https://www.google.com'),
-            method: LoadRequestMethod.get,
-            headers: const <String, String>{},
-          ),
+          LoadRequestParams(uri: Uri.parse('https://www.google.com')),
         );
 
         final NSUrlRequest request = verify(mockWebView.loadRequest(captureAny))
@@ -191,7 +263,6 @@
         await controller.loadRequest(
           LoadRequestParams(
             uri: Uri.parse('https://www.google.com'),
-            method: LoadRequestMethod.get,
             headers: const <String, String>{'a': 'header'},
           ),
         );
@@ -214,7 +285,6 @@
         await controller.loadRequest(LoadRequestParams(
           uri: Uri.parse('https://www.google.com'),
           method: LoadRequestMethod.post,
-          headers: const <String, String>{},
         ));
 
         final NSUrlRequest request = verify(mockWebView.loadRequest(captureAny))
@@ -235,7 +305,6 @@
           uri: Uri.parse('https://www.google.com'),
           method: LoadRequestMethod.post,
           body: Uint8List.fromList('Test Body'.codeUnits),
-          headers: const <String, String>{},
         ));
 
         final NSUrlRequest request = verify(mockWebView.loadRequest(captureAny))
@@ -309,14 +378,14 @@
       verify(mockWebView.reload());
     });
 
-    test('enableGestureNavigation', () async {
+    test('setAllowsBackForwardNavigationGestures', () async {
       final MockWKWebView mockWebView = MockWKWebView();
 
       final WebKitWebViewController controller = createControllerWithMocks(
         createMockWebView: (_, {dynamic observeValue}) => mockWebView,
       );
 
-      await controller.enableGestureNavigation(true);
+      await controller.setAllowsBackForwardNavigationGestures(true);
       verify(mockWebView.setAllowsBackForwardNavigationGestures(true));
     });
 
@@ -327,12 +396,13 @@
         createMockWebView: (_, {dynamic observeValue}) => mockWebView,
       );
 
+      final Object result = Object();
       when(mockWebView.evaluateJavaScript('runJavaScript')).thenAnswer(
-        (_) => Future<String>.value('returnString'),
+        (_) => Future<Object>.value(result),
       );
       expect(
         controller.runJavaScriptReturningResult('runJavaScript'),
-        completion('returnString'),
+        completion(result),
       );
     });
 
@@ -449,7 +519,7 @@
       );
       expect(
         controller.getScrollPosition(),
-        completion(const Point<double>(8.0, 16.0)),
+        completion(const Offset(8.0, 16.0)),
       );
     });
 
@@ -490,9 +560,12 @@
 
       controller.setBackgroundColor(Colors.red);
 
-      verify(mockWebView.setOpaque(false));
-      verify(mockWebView.setBackgroundColor(Colors.transparent));
-      verify(mockScrollView.setBackgroundColor(Colors.red));
+      // UIScrollView.setBackgroundColor must be called last.
+      verifyInOrder(<Object>[
+        mockWebView.setOpaque(false),
+        mockWebView.setBackgroundColor(Colors.transparent),
+        mockScrollView.setBackgroundColor(Colors.red),
+      ]);
     });
 
     test('userAgent', () async {
@@ -716,6 +789,7 @@
         const WebKitNavigationDelegateCreationParams(
           webKitProxy: WebKitProxy(
             createNavigationDelegate: CapturingNavigationDelegate.new,
+            createUIDelegate: CapturingUIDelegate.new,
           ),
         ),
       );
@@ -727,6 +801,11 @@
           CapturingNavigationDelegate.lastCreatedDelegate,
         ),
       );
+      verify(
+        mockWebView.setUIDelegate(
+          CapturingUIDelegate.lastCreatedDelegate,
+        ),
+      );
     });
 
     test('setPlatformNavigationDelegate onProgress', () async {
@@ -768,6 +847,7 @@
         const WebKitNavigationDelegateCreationParams(
           webKitProxy: WebKitProxy(
             createNavigationDelegate: CapturingNavigationDelegate.new,
+            createUIDelegate: WKUIDelegate.detached,
           ),
         ),
       );
@@ -787,6 +867,61 @@
 
       expect(callbackProgress, 0);
     });
+
+    test(
+        'setPlatformNavigationDelegate onProgress can be changed by the WebKitNavigationDelegage',
+        () async {
+      final MockWKWebView mockWebView = MockWKWebView();
+
+      late final void Function(
+        String keyPath,
+        NSObject object,
+        Map<NSKeyValueChangeKey, Object?> change,
+      ) webViewObserveValue;
+
+      final WebKitWebViewController controller = createControllerWithMocks(
+        createMockWebView: (
+          _, {
+          void Function(
+            String keyPath,
+            NSObject object,
+            Map<NSKeyValueChangeKey, Object?> change,
+          )?
+              observeValue,
+        }) {
+          webViewObserveValue = observeValue!;
+          return mockWebView;
+        },
+      );
+
+      final WebKitNavigationDelegate navigationDelegate =
+          WebKitNavigationDelegate(
+        const WebKitNavigationDelegateCreationParams(
+          webKitProxy: WebKitProxy(
+            createNavigationDelegate: CapturingNavigationDelegate.new,
+            createUIDelegate: WKUIDelegate.detached,
+          ),
+        ),
+      );
+
+      // First value of onProgress does nothing.
+      await navigationDelegate.setOnProgress((_) {});
+      await controller.setPlatformNavigationDelegate(navigationDelegate);
+
+      // Second value of onProgress sets `callbackProgress`.
+      late final int callbackProgress;
+      await navigationDelegate.setOnProgress(
+        (int progress) => callbackProgress = progress,
+      );
+
+      webViewObserveValue(
+        'estimatedProgress',
+        mockWebView,
+        <NSKeyValueChangeKey, Object?>{NSKeyValueChangeKey.newValue: 0.0},
+      );
+
+      expect(callbackProgress, 0);
+    });
   });
 
   group('WebKitJavaScriptChannelParams', () {
@@ -842,3 +977,11 @@
   static CapturingNavigationDelegate lastCreatedDelegate =
       CapturingNavigationDelegate();
 }
+
+// Records the last created instance of itself.
+class CapturingUIDelegate extends WKUIDelegate {
+  CapturingUIDelegate({super.onCreateWebView}) : super.detached() {
+    lastCreatedDelegate = this;
+  }
+  static CapturingUIDelegate lastCreatedDelegate = CapturingUIDelegate();
+}
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/test/webkit_webview_controller_test.mocks.dart b/packages/webview_flutter/webview_flutter_wkwebview/test/webkit_webview_controller_test.mocks.dart
new file mode 100644
index 0000000..288105c
--- /dev/null
+++ b/packages/webview_flutter/webview_flutter_wkwebview/test/webkit_webview_controller_test.mocks.dart
@@ -0,0 +1,833 @@
+// Mocks generated by Mockito 5.3.2 from annotations
+// in webview_flutter_wkwebview/test/webkit_webview_controller_test.dart.
+// Do not manually edit this file.
+
+// ignore_for_file: no_leading_underscores_for_library_prefixes
+import 'dart:async' as _i5;
+import 'dart:math' as _i2;
+import 'dart:ui' as _i6;
+
+import 'package:mockito/mockito.dart' as _i1;
+import 'package:webview_flutter_wkwebview/src/foundation/foundation.dart'
+    as _i7;
+import 'package:webview_flutter_wkwebview/src/ui_kit/ui_kit.dart' as _i3;
+import 'package:webview_flutter_wkwebview/src/web_kit/web_kit.dart' as _i4;
+
+// ignore_for_file: type=lint
+// ignore_for_file: avoid_redundant_argument_values
+// ignore_for_file: avoid_setters_without_getters
+// ignore_for_file: comment_references
+// ignore_for_file: implementation_imports
+// ignore_for_file: invalid_use_of_visible_for_testing_member
+// ignore_for_file: prefer_const_constructors
+// ignore_for_file: unnecessary_parenthesis
+// ignore_for_file: camel_case_types
+// ignore_for_file: subtype_of_sealed_class
+
+class _FakePoint_0<T extends num> extends _i1.SmartFake
+    implements _i2.Point<T> {
+  _FakePoint_0(
+    Object parent,
+    Invocation parentInvocation,
+  ) : super(
+          parent,
+          parentInvocation,
+        );
+}
+
+class _FakeUIScrollView_1 extends _i1.SmartFake implements _i3.UIScrollView {
+  _FakeUIScrollView_1(
+    Object parent,
+    Invocation parentInvocation,
+  ) : super(
+          parent,
+          parentInvocation,
+        );
+}
+
+class _FakeWKPreferences_2 extends _i1.SmartFake implements _i4.WKPreferences {
+  _FakeWKPreferences_2(
+    Object parent,
+    Invocation parentInvocation,
+  ) : super(
+          parent,
+          parentInvocation,
+        );
+}
+
+class _FakeWKUserContentController_3 extends _i1.SmartFake
+    implements _i4.WKUserContentController {
+  _FakeWKUserContentController_3(
+    Object parent,
+    Invocation parentInvocation,
+  ) : super(
+          parent,
+          parentInvocation,
+        );
+}
+
+class _FakeWKHttpCookieStore_4 extends _i1.SmartFake
+    implements _i4.WKHttpCookieStore {
+  _FakeWKHttpCookieStore_4(
+    Object parent,
+    Invocation parentInvocation,
+  ) : super(
+          parent,
+          parentInvocation,
+        );
+}
+
+class _FakeWKWebsiteDataStore_5 extends _i1.SmartFake
+    implements _i4.WKWebsiteDataStore {
+  _FakeWKWebsiteDataStore_5(
+    Object parent,
+    Invocation parentInvocation,
+  ) : super(
+          parent,
+          parentInvocation,
+        );
+}
+
+class _FakeWKWebViewConfiguration_6 extends _i1.SmartFake
+    implements _i4.WKWebViewConfiguration {
+  _FakeWKWebViewConfiguration_6(
+    Object parent,
+    Invocation parentInvocation,
+  ) : super(
+          parent,
+          parentInvocation,
+        );
+}
+
+class _FakeWKWebView_7 extends _i1.SmartFake implements _i4.WKWebView {
+  _FakeWKWebView_7(
+    Object parent,
+    Invocation parentInvocation,
+  ) : super(
+          parent,
+          parentInvocation,
+        );
+}
+
+/// A class which mocks [UIScrollView].
+///
+/// See the documentation for Mockito's code generation for more information.
+// ignore: must_be_immutable
+class MockUIScrollView extends _i1.Mock implements _i3.UIScrollView {
+  MockUIScrollView() {
+    _i1.throwOnMissingStub(this);
+  }
+
+  @override
+  _i5.Future<_i2.Point<double>> getContentOffset() => (super.noSuchMethod(
+        Invocation.method(
+          #getContentOffset,
+          [],
+        ),
+        returnValue: _i5.Future<_i2.Point<double>>.value(_FakePoint_0<double>(
+          this,
+          Invocation.method(
+            #getContentOffset,
+            [],
+          ),
+        )),
+      ) as _i5.Future<_i2.Point<double>>);
+  @override
+  _i5.Future<void> scrollBy(_i2.Point<double>? offset) => (super.noSuchMethod(
+        Invocation.method(
+          #scrollBy,
+          [offset],
+        ),
+        returnValue: _i5.Future<void>.value(),
+        returnValueForMissingStub: _i5.Future<void>.value(),
+      ) as _i5.Future<void>);
+  @override
+  _i5.Future<void> setContentOffset(_i2.Point<double>? offset) =>
+      (super.noSuchMethod(
+        Invocation.method(
+          #setContentOffset,
+          [offset],
+        ),
+        returnValue: _i5.Future<void>.value(),
+        returnValueForMissingStub: _i5.Future<void>.value(),
+      ) as _i5.Future<void>);
+  @override
+  _i3.UIScrollView copy() => (super.noSuchMethod(
+        Invocation.method(
+          #copy,
+          [],
+        ),
+        returnValue: _FakeUIScrollView_1(
+          this,
+          Invocation.method(
+            #copy,
+            [],
+          ),
+        ),
+      ) as _i3.UIScrollView);
+  @override
+  _i5.Future<void> setBackgroundColor(_i6.Color? color) => (super.noSuchMethod(
+        Invocation.method(
+          #setBackgroundColor,
+          [color],
+        ),
+        returnValue: _i5.Future<void>.value(),
+        returnValueForMissingStub: _i5.Future<void>.value(),
+      ) as _i5.Future<void>);
+  @override
+  _i5.Future<void> setOpaque(bool? opaque) => (super.noSuchMethod(
+        Invocation.method(
+          #setOpaque,
+          [opaque],
+        ),
+        returnValue: _i5.Future<void>.value(),
+        returnValueForMissingStub: _i5.Future<void>.value(),
+      ) as _i5.Future<void>);
+  @override
+  _i5.Future<void> addObserver(
+    _i7.NSObject? observer, {
+    required String? keyPath,
+    required Set<_i7.NSKeyValueObservingOptions>? options,
+  }) =>
+      (super.noSuchMethod(
+        Invocation.method(
+          #addObserver,
+          [observer],
+          {
+            #keyPath: keyPath,
+            #options: options,
+          },
+        ),
+        returnValue: _i5.Future<void>.value(),
+        returnValueForMissingStub: _i5.Future<void>.value(),
+      ) as _i5.Future<void>);
+  @override
+  _i5.Future<void> removeObserver(
+    _i7.NSObject? observer, {
+    required String? keyPath,
+  }) =>
+      (super.noSuchMethod(
+        Invocation.method(
+          #removeObserver,
+          [observer],
+          {#keyPath: keyPath},
+        ),
+        returnValue: _i5.Future<void>.value(),
+        returnValueForMissingStub: _i5.Future<void>.value(),
+      ) as _i5.Future<void>);
+}
+
+/// A class which mocks [WKPreferences].
+///
+/// See the documentation for Mockito's code generation for more information.
+// ignore: must_be_immutable
+class MockWKPreferences extends _i1.Mock implements _i4.WKPreferences {
+  MockWKPreferences() {
+    _i1.throwOnMissingStub(this);
+  }
+
+  @override
+  _i5.Future<void> setJavaScriptEnabled(bool? enabled) => (super.noSuchMethod(
+        Invocation.method(
+          #setJavaScriptEnabled,
+          [enabled],
+        ),
+        returnValue: _i5.Future<void>.value(),
+        returnValueForMissingStub: _i5.Future<void>.value(),
+      ) as _i5.Future<void>);
+  @override
+  _i4.WKPreferences copy() => (super.noSuchMethod(
+        Invocation.method(
+          #copy,
+          [],
+        ),
+        returnValue: _FakeWKPreferences_2(
+          this,
+          Invocation.method(
+            #copy,
+            [],
+          ),
+        ),
+      ) as _i4.WKPreferences);
+  @override
+  _i5.Future<void> addObserver(
+    _i7.NSObject? observer, {
+    required String? keyPath,
+    required Set<_i7.NSKeyValueObservingOptions>? options,
+  }) =>
+      (super.noSuchMethod(
+        Invocation.method(
+          #addObserver,
+          [observer],
+          {
+            #keyPath: keyPath,
+            #options: options,
+          },
+        ),
+        returnValue: _i5.Future<void>.value(),
+        returnValueForMissingStub: _i5.Future<void>.value(),
+      ) as _i5.Future<void>);
+  @override
+  _i5.Future<void> removeObserver(
+    _i7.NSObject? observer, {
+    required String? keyPath,
+  }) =>
+      (super.noSuchMethod(
+        Invocation.method(
+          #removeObserver,
+          [observer],
+          {#keyPath: keyPath},
+        ),
+        returnValue: _i5.Future<void>.value(),
+        returnValueForMissingStub: _i5.Future<void>.value(),
+      ) as _i5.Future<void>);
+}
+
+/// A class which mocks [WKUserContentController].
+///
+/// See the documentation for Mockito's code generation for more information.
+// ignore: must_be_immutable
+class MockWKUserContentController extends _i1.Mock
+    implements _i4.WKUserContentController {
+  MockWKUserContentController() {
+    _i1.throwOnMissingStub(this);
+  }
+
+  @override
+  _i5.Future<void> addScriptMessageHandler(
+    _i4.WKScriptMessageHandler? handler,
+    String? name,
+  ) =>
+      (super.noSuchMethod(
+        Invocation.method(
+          #addScriptMessageHandler,
+          [
+            handler,
+            name,
+          ],
+        ),
+        returnValue: _i5.Future<void>.value(),
+        returnValueForMissingStub: _i5.Future<void>.value(),
+      ) as _i5.Future<void>);
+  @override
+  _i5.Future<void> removeScriptMessageHandler(String? name) =>
+      (super.noSuchMethod(
+        Invocation.method(
+          #removeScriptMessageHandler,
+          [name],
+        ),
+        returnValue: _i5.Future<void>.value(),
+        returnValueForMissingStub: _i5.Future<void>.value(),
+      ) as _i5.Future<void>);
+  @override
+  _i5.Future<void> removeAllScriptMessageHandlers() => (super.noSuchMethod(
+        Invocation.method(
+          #removeAllScriptMessageHandlers,
+          [],
+        ),
+        returnValue: _i5.Future<void>.value(),
+        returnValueForMissingStub: _i5.Future<void>.value(),
+      ) as _i5.Future<void>);
+  @override
+  _i5.Future<void> addUserScript(_i4.WKUserScript? userScript) =>
+      (super.noSuchMethod(
+        Invocation.method(
+          #addUserScript,
+          [userScript],
+        ),
+        returnValue: _i5.Future<void>.value(),
+        returnValueForMissingStub: _i5.Future<void>.value(),
+      ) as _i5.Future<void>);
+  @override
+  _i5.Future<void> removeAllUserScripts() => (super.noSuchMethod(
+        Invocation.method(
+          #removeAllUserScripts,
+          [],
+        ),
+        returnValue: _i5.Future<void>.value(),
+        returnValueForMissingStub: _i5.Future<void>.value(),
+      ) as _i5.Future<void>);
+  @override
+  _i4.WKUserContentController copy() => (super.noSuchMethod(
+        Invocation.method(
+          #copy,
+          [],
+        ),
+        returnValue: _FakeWKUserContentController_3(
+          this,
+          Invocation.method(
+            #copy,
+            [],
+          ),
+        ),
+      ) as _i4.WKUserContentController);
+  @override
+  _i5.Future<void> addObserver(
+    _i7.NSObject? observer, {
+    required String? keyPath,
+    required Set<_i7.NSKeyValueObservingOptions>? options,
+  }) =>
+      (super.noSuchMethod(
+        Invocation.method(
+          #addObserver,
+          [observer],
+          {
+            #keyPath: keyPath,
+            #options: options,
+          },
+        ),
+        returnValue: _i5.Future<void>.value(),
+        returnValueForMissingStub: _i5.Future<void>.value(),
+      ) as _i5.Future<void>);
+  @override
+  _i5.Future<void> removeObserver(
+    _i7.NSObject? observer, {
+    required String? keyPath,
+  }) =>
+      (super.noSuchMethod(
+        Invocation.method(
+          #removeObserver,
+          [observer],
+          {#keyPath: keyPath},
+        ),
+        returnValue: _i5.Future<void>.value(),
+        returnValueForMissingStub: _i5.Future<void>.value(),
+      ) as _i5.Future<void>);
+}
+
+/// A class which mocks [WKWebsiteDataStore].
+///
+/// See the documentation for Mockito's code generation for more information.
+// ignore: must_be_immutable
+class MockWKWebsiteDataStore extends _i1.Mock
+    implements _i4.WKWebsiteDataStore {
+  MockWKWebsiteDataStore() {
+    _i1.throwOnMissingStub(this);
+  }
+
+  @override
+  _i4.WKHttpCookieStore get httpCookieStore => (super.noSuchMethod(
+        Invocation.getter(#httpCookieStore),
+        returnValue: _FakeWKHttpCookieStore_4(
+          this,
+          Invocation.getter(#httpCookieStore),
+        ),
+      ) as _i4.WKHttpCookieStore);
+  @override
+  _i5.Future<bool> removeDataOfTypes(
+    Set<_i4.WKWebsiteDataType>? dataTypes,
+    DateTime? since,
+  ) =>
+      (super.noSuchMethod(
+        Invocation.method(
+          #removeDataOfTypes,
+          [
+            dataTypes,
+            since,
+          ],
+        ),
+        returnValue: _i5.Future<bool>.value(false),
+      ) as _i5.Future<bool>);
+  @override
+  _i4.WKWebsiteDataStore copy() => (super.noSuchMethod(
+        Invocation.method(
+          #copy,
+          [],
+        ),
+        returnValue: _FakeWKWebsiteDataStore_5(
+          this,
+          Invocation.method(
+            #copy,
+            [],
+          ),
+        ),
+      ) as _i4.WKWebsiteDataStore);
+  @override
+  _i5.Future<void> addObserver(
+    _i7.NSObject? observer, {
+    required String? keyPath,
+    required Set<_i7.NSKeyValueObservingOptions>? options,
+  }) =>
+      (super.noSuchMethod(
+        Invocation.method(
+          #addObserver,
+          [observer],
+          {
+            #keyPath: keyPath,
+            #options: options,
+          },
+        ),
+        returnValue: _i5.Future<void>.value(),
+        returnValueForMissingStub: _i5.Future<void>.value(),
+      ) as _i5.Future<void>);
+  @override
+  _i5.Future<void> removeObserver(
+    _i7.NSObject? observer, {
+    required String? keyPath,
+  }) =>
+      (super.noSuchMethod(
+        Invocation.method(
+          #removeObserver,
+          [observer],
+          {#keyPath: keyPath},
+        ),
+        returnValue: _i5.Future<void>.value(),
+        returnValueForMissingStub: _i5.Future<void>.value(),
+      ) as _i5.Future<void>);
+}
+
+/// A class which mocks [WKWebView].
+///
+/// See the documentation for Mockito's code generation for more information.
+// ignore: must_be_immutable
+class MockWKWebView extends _i1.Mock implements _i4.WKWebView {
+  MockWKWebView() {
+    _i1.throwOnMissingStub(this);
+  }
+
+  @override
+  _i4.WKWebViewConfiguration get configuration => (super.noSuchMethod(
+        Invocation.getter(#configuration),
+        returnValue: _FakeWKWebViewConfiguration_6(
+          this,
+          Invocation.getter(#configuration),
+        ),
+      ) as _i4.WKWebViewConfiguration);
+  @override
+  _i3.UIScrollView get scrollView => (super.noSuchMethod(
+        Invocation.getter(#scrollView),
+        returnValue: _FakeUIScrollView_1(
+          this,
+          Invocation.getter(#scrollView),
+        ),
+      ) as _i3.UIScrollView);
+  @override
+  _i5.Future<void> setUIDelegate(_i4.WKUIDelegate? delegate) =>
+      (super.noSuchMethod(
+        Invocation.method(
+          #setUIDelegate,
+          [delegate],
+        ),
+        returnValue: _i5.Future<void>.value(),
+        returnValueForMissingStub: _i5.Future<void>.value(),
+      ) as _i5.Future<void>);
+  @override
+  _i5.Future<void> setNavigationDelegate(_i4.WKNavigationDelegate? delegate) =>
+      (super.noSuchMethod(
+        Invocation.method(
+          #setNavigationDelegate,
+          [delegate],
+        ),
+        returnValue: _i5.Future<void>.value(),
+        returnValueForMissingStub: _i5.Future<void>.value(),
+      ) as _i5.Future<void>);
+  @override
+  _i5.Future<String?> getUrl() => (super.noSuchMethod(
+        Invocation.method(
+          #getUrl,
+          [],
+        ),
+        returnValue: _i5.Future<String?>.value(),
+      ) as _i5.Future<String?>);
+  @override
+  _i5.Future<double> getEstimatedProgress() => (super.noSuchMethod(
+        Invocation.method(
+          #getEstimatedProgress,
+          [],
+        ),
+        returnValue: _i5.Future<double>.value(0.0),
+      ) as _i5.Future<double>);
+  @override
+  _i5.Future<void> loadRequest(_i7.NSUrlRequest? request) =>
+      (super.noSuchMethod(
+        Invocation.method(
+          #loadRequest,
+          [request],
+        ),
+        returnValue: _i5.Future<void>.value(),
+        returnValueForMissingStub: _i5.Future<void>.value(),
+      ) as _i5.Future<void>);
+  @override
+  _i5.Future<void> loadHtmlString(
+    String? string, {
+    String? baseUrl,
+  }) =>
+      (super.noSuchMethod(
+        Invocation.method(
+          #loadHtmlString,
+          [string],
+          {#baseUrl: baseUrl},
+        ),
+        returnValue: _i5.Future<void>.value(),
+        returnValueForMissingStub: _i5.Future<void>.value(),
+      ) as _i5.Future<void>);
+  @override
+  _i5.Future<void> loadFileUrl(
+    String? url, {
+    required String? readAccessUrl,
+  }) =>
+      (super.noSuchMethod(
+        Invocation.method(
+          #loadFileUrl,
+          [url],
+          {#readAccessUrl: readAccessUrl},
+        ),
+        returnValue: _i5.Future<void>.value(),
+        returnValueForMissingStub: _i5.Future<void>.value(),
+      ) as _i5.Future<void>);
+  @override
+  _i5.Future<void> loadFlutterAsset(String? key) => (super.noSuchMethod(
+        Invocation.method(
+          #loadFlutterAsset,
+          [key],
+        ),
+        returnValue: _i5.Future<void>.value(),
+        returnValueForMissingStub: _i5.Future<void>.value(),
+      ) as _i5.Future<void>);
+  @override
+  _i5.Future<bool> canGoBack() => (super.noSuchMethod(
+        Invocation.method(
+          #canGoBack,
+          [],
+        ),
+        returnValue: _i5.Future<bool>.value(false),
+      ) as _i5.Future<bool>);
+  @override
+  _i5.Future<bool> canGoForward() => (super.noSuchMethod(
+        Invocation.method(
+          #canGoForward,
+          [],
+        ),
+        returnValue: _i5.Future<bool>.value(false),
+      ) as _i5.Future<bool>);
+  @override
+  _i5.Future<void> goBack() => (super.noSuchMethod(
+        Invocation.method(
+          #goBack,
+          [],
+        ),
+        returnValue: _i5.Future<void>.value(),
+        returnValueForMissingStub: _i5.Future<void>.value(),
+      ) as _i5.Future<void>);
+  @override
+  _i5.Future<void> goForward() => (super.noSuchMethod(
+        Invocation.method(
+          #goForward,
+          [],
+        ),
+        returnValue: _i5.Future<void>.value(),
+        returnValueForMissingStub: _i5.Future<void>.value(),
+      ) as _i5.Future<void>);
+  @override
+  _i5.Future<void> reload() => (super.noSuchMethod(
+        Invocation.method(
+          #reload,
+          [],
+        ),
+        returnValue: _i5.Future<void>.value(),
+        returnValueForMissingStub: _i5.Future<void>.value(),
+      ) as _i5.Future<void>);
+  @override
+  _i5.Future<String?> getTitle() => (super.noSuchMethod(
+        Invocation.method(
+          #getTitle,
+          [],
+        ),
+        returnValue: _i5.Future<String?>.value(),
+      ) as _i5.Future<String?>);
+  @override
+  _i5.Future<void> setAllowsBackForwardNavigationGestures(bool? allow) =>
+      (super.noSuchMethod(
+        Invocation.method(
+          #setAllowsBackForwardNavigationGestures,
+          [allow],
+        ),
+        returnValue: _i5.Future<void>.value(),
+        returnValueForMissingStub: _i5.Future<void>.value(),
+      ) as _i5.Future<void>);
+  @override
+  _i5.Future<void> setCustomUserAgent(String? userAgent) => (super.noSuchMethod(
+        Invocation.method(
+          #setCustomUserAgent,
+          [userAgent],
+        ),
+        returnValue: _i5.Future<void>.value(),
+        returnValueForMissingStub: _i5.Future<void>.value(),
+      ) as _i5.Future<void>);
+  @override
+  _i5.Future<Object?> evaluateJavaScript(String? javaScriptString) =>
+      (super.noSuchMethod(
+        Invocation.method(
+          #evaluateJavaScript,
+          [javaScriptString],
+        ),
+        returnValue: _i5.Future<Object?>.value(),
+      ) as _i5.Future<Object?>);
+  @override
+  _i4.WKWebView copy() => (super.noSuchMethod(
+        Invocation.method(
+          #copy,
+          [],
+        ),
+        returnValue: _FakeWKWebView_7(
+          this,
+          Invocation.method(
+            #copy,
+            [],
+          ),
+        ),
+      ) as _i4.WKWebView);
+  @override
+  _i5.Future<void> setBackgroundColor(_i6.Color? color) => (super.noSuchMethod(
+        Invocation.method(
+          #setBackgroundColor,
+          [color],
+        ),
+        returnValue: _i5.Future<void>.value(),
+        returnValueForMissingStub: _i5.Future<void>.value(),
+      ) as _i5.Future<void>);
+  @override
+  _i5.Future<void> setOpaque(bool? opaque) => (super.noSuchMethod(
+        Invocation.method(
+          #setOpaque,
+          [opaque],
+        ),
+        returnValue: _i5.Future<void>.value(),
+        returnValueForMissingStub: _i5.Future<void>.value(),
+      ) as _i5.Future<void>);
+  @override
+  _i5.Future<void> addObserver(
+    _i7.NSObject? observer, {
+    required String? keyPath,
+    required Set<_i7.NSKeyValueObservingOptions>? options,
+  }) =>
+      (super.noSuchMethod(
+        Invocation.method(
+          #addObserver,
+          [observer],
+          {
+            #keyPath: keyPath,
+            #options: options,
+          },
+        ),
+        returnValue: _i5.Future<void>.value(),
+        returnValueForMissingStub: _i5.Future<void>.value(),
+      ) as _i5.Future<void>);
+  @override
+  _i5.Future<void> removeObserver(
+    _i7.NSObject? observer, {
+    required String? keyPath,
+  }) =>
+      (super.noSuchMethod(
+        Invocation.method(
+          #removeObserver,
+          [observer],
+          {#keyPath: keyPath},
+        ),
+        returnValue: _i5.Future<void>.value(),
+        returnValueForMissingStub: _i5.Future<void>.value(),
+      ) as _i5.Future<void>);
+}
+
+/// A class which mocks [WKWebViewConfiguration].
+///
+/// See the documentation for Mockito's code generation for more information.
+// ignore: must_be_immutable
+class MockWKWebViewConfiguration extends _i1.Mock
+    implements _i4.WKWebViewConfiguration {
+  MockWKWebViewConfiguration() {
+    _i1.throwOnMissingStub(this);
+  }
+
+  @override
+  _i4.WKUserContentController get userContentController => (super.noSuchMethod(
+        Invocation.getter(#userContentController),
+        returnValue: _FakeWKUserContentController_3(
+          this,
+          Invocation.getter(#userContentController),
+        ),
+      ) as _i4.WKUserContentController);
+  @override
+  _i4.WKPreferences get preferences => (super.noSuchMethod(
+        Invocation.getter(#preferences),
+        returnValue: _FakeWKPreferences_2(
+          this,
+          Invocation.getter(#preferences),
+        ),
+      ) as _i4.WKPreferences);
+  @override
+  _i4.WKWebsiteDataStore get websiteDataStore => (super.noSuchMethod(
+        Invocation.getter(#websiteDataStore),
+        returnValue: _FakeWKWebsiteDataStore_5(
+          this,
+          Invocation.getter(#websiteDataStore),
+        ),
+      ) as _i4.WKWebsiteDataStore);
+  @override
+  _i5.Future<void> setAllowsInlineMediaPlayback(bool? allow) =>
+      (super.noSuchMethod(
+        Invocation.method(
+          #setAllowsInlineMediaPlayback,
+          [allow],
+        ),
+        returnValue: _i5.Future<void>.value(),
+        returnValueForMissingStub: _i5.Future<void>.value(),
+      ) as _i5.Future<void>);
+  @override
+  _i5.Future<void> setMediaTypesRequiringUserActionForPlayback(
+          Set<_i4.WKAudiovisualMediaType>? types) =>
+      (super.noSuchMethod(
+        Invocation.method(
+          #setMediaTypesRequiringUserActionForPlayback,
+          [types],
+        ),
+        returnValue: _i5.Future<void>.value(),
+        returnValueForMissingStub: _i5.Future<void>.value(),
+      ) as _i5.Future<void>);
+  @override
+  _i4.WKWebViewConfiguration copy() => (super.noSuchMethod(
+        Invocation.method(
+          #copy,
+          [],
+        ),
+        returnValue: _FakeWKWebViewConfiguration_6(
+          this,
+          Invocation.method(
+            #copy,
+            [],
+          ),
+        ),
+      ) as _i4.WKWebViewConfiguration);
+  @override
+  _i5.Future<void> addObserver(
+    _i7.NSObject? observer, {
+    required String? keyPath,
+    required Set<_i7.NSKeyValueObservingOptions>? options,
+  }) =>
+      (super.noSuchMethod(
+        Invocation.method(
+          #addObserver,
+          [observer],
+          {
+            #keyPath: keyPath,
+            #options: options,
+          },
+        ),
+        returnValue: _i5.Future<void>.value(),
+        returnValueForMissingStub: _i5.Future<void>.value(),
+      ) as _i5.Future<void>);
+  @override
+  _i5.Future<void> removeObserver(
+    _i7.NSObject? observer, {
+    required String? keyPath,
+  }) =>
+      (super.noSuchMethod(
+        Invocation.method(
+          #removeObserver,
+          [observer],
+          {#keyPath: keyPath},
+        ),
+        returnValue: _i5.Future<void>.value(),
+        returnValueForMissingStub: _i5.Future<void>.value(),
+      ) as _i5.Future<void>);
+}
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/test/v4/webkit_webview_cookie_manager_test.dart b/packages/webview_flutter/webview_flutter_wkwebview/test/webkit_webview_cookie_manager_test.dart
similarity index 93%
rename from packages/webview_flutter/webview_flutter_wkwebview/test/v4/webkit_webview_cookie_manager_test.dart
rename to packages/webview_flutter/webview_flutter_wkwebview/test/webkit_webview_cookie_manager_test.dart
index 71107cb..a9dd742 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/test/v4/webkit_webview_cookie_manager_test.dart
+++ b/packages/webview_flutter/webview_flutter_wkwebview/test/webkit_webview_cookie_manager_test.dart
@@ -6,11 +6,11 @@
 import 'package:flutter_test/flutter_test.dart';
 import 'package:mockito/annotations.dart';
 import 'package:mockito/mockito.dart';
-import 'package:webview_flutter_platform_interface/v4/webview_flutter_platform_interface.dart';
+import 'package:webview_flutter_platform_interface/webview_flutter_platform_interface.dart';
 import 'package:webview_flutter_wkwebview/src/foundation/foundation.dart';
-import 'package:webview_flutter_wkwebview/src/v4/src/webkit_proxy.dart';
-import 'package:webview_flutter_wkwebview/src/v4/webview_flutter_wkwebview.dart';
 import 'package:webview_flutter_wkwebview/src/web_kit/web_kit.dart';
+import 'package:webview_flutter_wkwebview/src/webkit_proxy.dart';
+import 'package:webview_flutter_wkwebview/webview_flutter_wkwebview.dart';
 
 import 'webkit_webview_cookie_manager_test.mocks.dart';
 
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/test/webkit_webview_cookie_manager_test.mocks.dart b/packages/webview_flutter/webview_flutter_wkwebview/test/webkit_webview_cookie_manager_test.mocks.dart
new file mode 100644
index 0000000..c552d96
--- /dev/null
+++ b/packages/webview_flutter/webview_flutter_wkwebview/test/webkit_webview_cookie_manager_test.mocks.dart
@@ -0,0 +1,191 @@
+// Mocks generated by Mockito 5.3.2 from annotations
+// in webview_flutter_wkwebview/test/webkit_webview_cookie_manager_test.dart.
+// Do not manually edit this file.
+
+// ignore_for_file: no_leading_underscores_for_library_prefixes
+import 'dart:async' as _i3;
+
+import 'package:mockito/mockito.dart' as _i1;
+import 'package:webview_flutter_wkwebview/src/foundation/foundation.dart'
+    as _i4;
+import 'package:webview_flutter_wkwebview/src/web_kit/web_kit.dart' as _i2;
+
+// ignore_for_file: type=lint
+// ignore_for_file: avoid_redundant_argument_values
+// ignore_for_file: avoid_setters_without_getters
+// ignore_for_file: comment_references
+// ignore_for_file: implementation_imports
+// ignore_for_file: invalid_use_of_visible_for_testing_member
+// ignore_for_file: prefer_const_constructors
+// ignore_for_file: unnecessary_parenthesis
+// ignore_for_file: camel_case_types
+// ignore_for_file: subtype_of_sealed_class
+
+class _FakeWKHttpCookieStore_0 extends _i1.SmartFake
+    implements _i2.WKHttpCookieStore {
+  _FakeWKHttpCookieStore_0(
+    Object parent,
+    Invocation parentInvocation,
+  ) : super(
+          parent,
+          parentInvocation,
+        );
+}
+
+class _FakeWKWebsiteDataStore_1 extends _i1.SmartFake
+    implements _i2.WKWebsiteDataStore {
+  _FakeWKWebsiteDataStore_1(
+    Object parent,
+    Invocation parentInvocation,
+  ) : super(
+          parent,
+          parentInvocation,
+        );
+}
+
+/// A class which mocks [WKWebsiteDataStore].
+///
+/// See the documentation for Mockito's code generation for more information.
+// ignore: must_be_immutable
+class MockWKWebsiteDataStore extends _i1.Mock
+    implements _i2.WKWebsiteDataStore {
+  MockWKWebsiteDataStore() {
+    _i1.throwOnMissingStub(this);
+  }
+
+  @override
+  _i2.WKHttpCookieStore get httpCookieStore => (super.noSuchMethod(
+        Invocation.getter(#httpCookieStore),
+        returnValue: _FakeWKHttpCookieStore_0(
+          this,
+          Invocation.getter(#httpCookieStore),
+        ),
+      ) as _i2.WKHttpCookieStore);
+  @override
+  _i3.Future<bool> removeDataOfTypes(
+    Set<_i2.WKWebsiteDataType>? dataTypes,
+    DateTime? since,
+  ) =>
+      (super.noSuchMethod(
+        Invocation.method(
+          #removeDataOfTypes,
+          [
+            dataTypes,
+            since,
+          ],
+        ),
+        returnValue: _i3.Future<bool>.value(false),
+      ) as _i3.Future<bool>);
+  @override
+  _i2.WKWebsiteDataStore copy() => (super.noSuchMethod(
+        Invocation.method(
+          #copy,
+          [],
+        ),
+        returnValue: _FakeWKWebsiteDataStore_1(
+          this,
+          Invocation.method(
+            #copy,
+            [],
+          ),
+        ),
+      ) as _i2.WKWebsiteDataStore);
+  @override
+  _i3.Future<void> addObserver(
+    _i4.NSObject? observer, {
+    required String? keyPath,
+    required Set<_i4.NSKeyValueObservingOptions>? options,
+  }) =>
+      (super.noSuchMethod(
+        Invocation.method(
+          #addObserver,
+          [observer],
+          {
+            #keyPath: keyPath,
+            #options: options,
+          },
+        ),
+        returnValue: _i3.Future<void>.value(),
+        returnValueForMissingStub: _i3.Future<void>.value(),
+      ) as _i3.Future<void>);
+  @override
+  _i3.Future<void> removeObserver(
+    _i4.NSObject? observer, {
+    required String? keyPath,
+  }) =>
+      (super.noSuchMethod(
+        Invocation.method(
+          #removeObserver,
+          [observer],
+          {#keyPath: keyPath},
+        ),
+        returnValue: _i3.Future<void>.value(),
+        returnValueForMissingStub: _i3.Future<void>.value(),
+      ) as _i3.Future<void>);
+}
+
+/// A class which mocks [WKHttpCookieStore].
+///
+/// See the documentation for Mockito's code generation for more information.
+// ignore: must_be_immutable
+class MockWKHttpCookieStore extends _i1.Mock implements _i2.WKHttpCookieStore {
+  MockWKHttpCookieStore() {
+    _i1.throwOnMissingStub(this);
+  }
+
+  @override
+  _i3.Future<void> setCookie(_i4.NSHttpCookie? cookie) => (super.noSuchMethod(
+        Invocation.method(
+          #setCookie,
+          [cookie],
+        ),
+        returnValue: _i3.Future<void>.value(),
+        returnValueForMissingStub: _i3.Future<void>.value(),
+      ) as _i3.Future<void>);
+  @override
+  _i2.WKHttpCookieStore copy() => (super.noSuchMethod(
+        Invocation.method(
+          #copy,
+          [],
+        ),
+        returnValue: _FakeWKHttpCookieStore_0(
+          this,
+          Invocation.method(
+            #copy,
+            [],
+          ),
+        ),
+      ) as _i2.WKHttpCookieStore);
+  @override
+  _i3.Future<void> addObserver(
+    _i4.NSObject? observer, {
+    required String? keyPath,
+    required Set<_i4.NSKeyValueObservingOptions>? options,
+  }) =>
+      (super.noSuchMethod(
+        Invocation.method(
+          #addObserver,
+          [observer],
+          {
+            #keyPath: keyPath,
+            #options: options,
+          },
+        ),
+        returnValue: _i3.Future<void>.value(),
+        returnValueForMissingStub: _i3.Future<void>.value(),
+      ) as _i3.Future<void>);
+  @override
+  _i3.Future<void> removeObserver(
+    _i4.NSObject? observer, {
+    required String? keyPath,
+  }) =>
+      (super.noSuchMethod(
+        Invocation.method(
+          #removeObserver,
+          [observer],
+          {#keyPath: keyPath},
+        ),
+        returnValue: _i3.Future<void>.value(),
+        returnValueForMissingStub: _i3.Future<void>.value(),
+      ) as _i3.Future<void>);
+}
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/test/v4/webkit_webview_widget_test.dart b/packages/webview_flutter/webview_flutter_wkwebview/test/webkit_webview_widget_test.dart
similarity index 80%
rename from packages/webview_flutter/webview_flutter_wkwebview/test/v4/webkit_webview_widget_test.dart
rename to packages/webview_flutter/webview_flutter_wkwebview/test/webkit_webview_widget_test.dart
index 36a95d6..2e0d6e3 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/test/v4/webkit_webview_widget_test.dart
+++ b/packages/webview_flutter/webview_flutter_wkwebview/test/webkit_webview_widget_test.dart
@@ -4,12 +4,16 @@
 
 import 'package:flutter/material.dart';
 import 'package:flutter_test/flutter_test.dart';
+import 'package:mockito/annotations.dart';
 import 'package:webview_flutter_wkwebview/src/common/instance_manager.dart';
 import 'package:webview_flutter_wkwebview/src/foundation/foundation.dart';
-import 'package:webview_flutter_wkwebview/src/v4/src/webkit_proxy.dart';
-import 'package:webview_flutter_wkwebview/src/v4/webview_flutter_wkwebview.dart';
 import 'package:webview_flutter_wkwebview/src/web_kit/web_kit.dart';
+import 'package:webview_flutter_wkwebview/src/webkit_proxy.dart';
+import 'package:webview_flutter_wkwebview/webview_flutter_wkwebview.dart';
 
+import 'webkit_webview_widget_test.mocks.dart';
+
+@GenerateMocks(<Type>[WKWebViewConfiguration])
 void main() {
   TestWidgetsFlutterBinding.ensureInitialized();
 
@@ -37,13 +41,14 @@
               instanceManager.addDartCreatedInstance(webView);
               return webView;
             },
-            createWebViewConfiguration: WKWebViewConfiguration.detached,
+            createWebViewConfiguration: () => MockWKWebViewConfiguration(),
           ),
         ),
       );
 
       final WebKitWebViewWidget widget = WebKitWebViewWidget(
         WebKitWebViewWidgetCreationParams(
+          key: const Key('keyValue'),
           controller: controller,
           instanceManager: instanceManager,
         ),
@@ -54,6 +59,7 @@
       );
 
       expect(find.byType(UiKitView), findsOneWidget);
+      expect(find.byKey(const Key('keyValue')), findsOneWidget);
     });
   });
 }
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/test/webkit_webview_widget_test.mocks.dart b/packages/webview_flutter/webview_flutter_wkwebview/test/webkit_webview_widget_test.mocks.dart
new file mode 100644
index 0000000..0f48af4
--- /dev/null
+++ b/packages/webview_flutter/webview_flutter_wkwebview/test/webkit_webview_widget_test.mocks.dart
@@ -0,0 +1,168 @@
+// Mocks generated by Mockito 5.3.2 from annotations
+// in webview_flutter_wkwebview/test/webkit_webview_widget_test.dart.
+// Do not manually edit this file.
+
+// ignore_for_file: no_leading_underscores_for_library_prefixes
+import 'dart:async' as _i3;
+
+import 'package:mockito/mockito.dart' as _i1;
+import 'package:webview_flutter_wkwebview/src/foundation/foundation.dart'
+    as _i4;
+import 'package:webview_flutter_wkwebview/src/web_kit/web_kit.dart' as _i2;
+
+// ignore_for_file: type=lint
+// ignore_for_file: avoid_redundant_argument_values
+// ignore_for_file: avoid_setters_without_getters
+// ignore_for_file: comment_references
+// ignore_for_file: implementation_imports
+// ignore_for_file: invalid_use_of_visible_for_testing_member
+// ignore_for_file: prefer_const_constructors
+// ignore_for_file: unnecessary_parenthesis
+// ignore_for_file: camel_case_types
+// ignore_for_file: subtype_of_sealed_class
+
+class _FakeWKUserContentController_0 extends _i1.SmartFake
+    implements _i2.WKUserContentController {
+  _FakeWKUserContentController_0(
+    Object parent,
+    Invocation parentInvocation,
+  ) : super(
+          parent,
+          parentInvocation,
+        );
+}
+
+class _FakeWKPreferences_1 extends _i1.SmartFake implements _i2.WKPreferences {
+  _FakeWKPreferences_1(
+    Object parent,
+    Invocation parentInvocation,
+  ) : super(
+          parent,
+          parentInvocation,
+        );
+}
+
+class _FakeWKWebsiteDataStore_2 extends _i1.SmartFake
+    implements _i2.WKWebsiteDataStore {
+  _FakeWKWebsiteDataStore_2(
+    Object parent,
+    Invocation parentInvocation,
+  ) : super(
+          parent,
+          parentInvocation,
+        );
+}
+
+class _FakeWKWebViewConfiguration_3 extends _i1.SmartFake
+    implements _i2.WKWebViewConfiguration {
+  _FakeWKWebViewConfiguration_3(
+    Object parent,
+    Invocation parentInvocation,
+  ) : super(
+          parent,
+          parentInvocation,
+        );
+}
+
+/// A class which mocks [WKWebViewConfiguration].
+///
+/// See the documentation for Mockito's code generation for more information.
+// ignore: must_be_immutable
+class MockWKWebViewConfiguration extends _i1.Mock
+    implements _i2.WKWebViewConfiguration {
+  MockWKWebViewConfiguration() {
+    _i1.throwOnMissingStub(this);
+  }
+
+  @override
+  _i2.WKUserContentController get userContentController => (super.noSuchMethod(
+        Invocation.getter(#userContentController),
+        returnValue: _FakeWKUserContentController_0(
+          this,
+          Invocation.getter(#userContentController),
+        ),
+      ) as _i2.WKUserContentController);
+  @override
+  _i2.WKPreferences get preferences => (super.noSuchMethod(
+        Invocation.getter(#preferences),
+        returnValue: _FakeWKPreferences_1(
+          this,
+          Invocation.getter(#preferences),
+        ),
+      ) as _i2.WKPreferences);
+  @override
+  _i2.WKWebsiteDataStore get websiteDataStore => (super.noSuchMethod(
+        Invocation.getter(#websiteDataStore),
+        returnValue: _FakeWKWebsiteDataStore_2(
+          this,
+          Invocation.getter(#websiteDataStore),
+        ),
+      ) as _i2.WKWebsiteDataStore);
+  @override
+  _i3.Future<void> setAllowsInlineMediaPlayback(bool? allow) =>
+      (super.noSuchMethod(
+        Invocation.method(
+          #setAllowsInlineMediaPlayback,
+          [allow],
+        ),
+        returnValue: _i3.Future<void>.value(),
+        returnValueForMissingStub: _i3.Future<void>.value(),
+      ) as _i3.Future<void>);
+  @override
+  _i3.Future<void> setMediaTypesRequiringUserActionForPlayback(
+          Set<_i2.WKAudiovisualMediaType>? types) =>
+      (super.noSuchMethod(
+        Invocation.method(
+          #setMediaTypesRequiringUserActionForPlayback,
+          [types],
+        ),
+        returnValue: _i3.Future<void>.value(),
+        returnValueForMissingStub: _i3.Future<void>.value(),
+      ) as _i3.Future<void>);
+  @override
+  _i2.WKWebViewConfiguration copy() => (super.noSuchMethod(
+        Invocation.method(
+          #copy,
+          [],
+        ),
+        returnValue: _FakeWKWebViewConfiguration_3(
+          this,
+          Invocation.method(
+            #copy,
+            [],
+          ),
+        ),
+      ) as _i2.WKWebViewConfiguration);
+  @override
+  _i3.Future<void> addObserver(
+    _i4.NSObject? observer, {
+    required String? keyPath,
+    required Set<_i4.NSKeyValueObservingOptions>? options,
+  }) =>
+      (super.noSuchMethod(
+        Invocation.method(
+          #addObserver,
+          [observer],
+          {
+            #keyPath: keyPath,
+            #options: options,
+          },
+        ),
+        returnValue: _i3.Future<void>.value(),
+        returnValueForMissingStub: _i3.Future<void>.value(),
+      ) as _i3.Future<void>);
+  @override
+  _i3.Future<void> removeObserver(
+    _i4.NSObject? observer, {
+    required String? keyPath,
+  }) =>
+      (super.noSuchMethod(
+        Invocation.method(
+          #removeObserver,
+          [observer],
+          {#keyPath: keyPath},
+        ),
+        returnValue: _i3.Future<void>.value(),
+        returnValueForMissingStub: _i3.Future<void>.value(),
+      ) as _i3.Future<void>);
+}
diff --git a/script/configs/exclude_all_plugins_app.yaml b/script/configs/exclude_all_plugins_app.yaml
index bf00b6c..c7d589e 100644
--- a/script/configs/exclude_all_plugins_app.yaml
+++ b/script/configs/exclude_all_plugins_app.yaml
@@ -12,4 +12,5 @@
 # interface. Remove packages with release of `webview_flutter` 4.0.0. See
 # https://github.com/flutter/flutter/issues/94051.
 - webview_flutter_platform_interface
+- webview_flutter_wkwebview
 - webview_flutter_android