[webview_flutter] Initial v4.0 platform interface implementation  (#5109)

diff --git a/packages/webview_flutter/webview_flutter_platform_interface/CHANGELOG.md b/packages/webview_flutter/webview_flutter_platform_interface/CHANGELOG.md
index c7462dd..8f6c413 100644
--- a/packages/webview_flutter/webview_flutter_platform_interface/CHANGELOG.md
+++ b/packages/webview_flutter/webview_flutter_platform_interface/CHANGELOG.md
@@ -1,5 +1,6 @@
-## NEXT
+## 1.9.0
 
+* Adds the first iteration of the v4 webview_flutter interface implementation.
 * Removes unnecessary imports.
 
 ## 1.8.2
diff --git a/packages/webview_flutter/webview_flutter_platform_interface/lib/v4/src/platform_navigation_delegate.dart b/packages/webview_flutter/webview_flutter_platform_interface/lib/v4/src/platform_navigation_delegate.dart
new file mode 100644
index 0000000..a66f1de
--- /dev/null
+++ b/packages/webview_flutter/webview_flutter_platform_interface/lib/v4/src/platform_navigation_delegate.dart
@@ -0,0 +1,89 @@
+// 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.
+
+import 'dart:async';
+
+import 'package:flutter/foundation.dart';
+import 'package:plugin_platform_interface/plugin_platform_interface.dart';
+
+import 'webview_platform.dart';
+
+/// An interface defining navigation events that occur on the native platform.
+///
+/// The [PlatformWebViewController] is notifying this delegate on events that
+/// happened on the platform's webview. Platform implementations should
+/// implement this class and pass an instance to the [PlatformWebViewController].
+abstract class PlatformNavigationDelegate extends PlatformInterface {
+  /// Creates a new [PlatformNavigationDelegate]
+  factory PlatformNavigationDelegate(
+      PlatformNavigationDelegateCreationParams params) {
+    final PlatformNavigationDelegate callbackDelegate =
+        WebViewPlatform.instance!.createPlatformNavigationDelegate(params);
+    PlatformInterface.verify(callbackDelegate, _token);
+    return callbackDelegate;
+  }
+
+  /// Used by the platform implementation to create a new [PlatformNavigationDelegate].
+  ///
+  /// Should only be used by platform implementations because they can't extend
+  /// a class that only contains a factory constructor.
+  @protected
+  PlatformNavigationDelegate.implementation(this.params) : super(token: _token);
+
+  static final Object _token = Object();
+
+  /// The parameters used to initialize the [PlatformNavigationDelegate].
+  final PlatformNavigationDelegateCreationParams params;
+
+  /// Invoked when a navigation request is pending.
+  ///
+  /// See [PlatformWebViewController.setPlatformNavigationDelegate].
+  Future<void> setOnNavigationRequest(
+    FutureOr<bool> Function({required String url, required bool isForMainFrame})
+        onNavigationRequest,
+  ) {
+    throw UnimplementedError(
+        'setOnNavigationRequest is not implemented on the current platform.');
+  }
+
+  /// Invoked when a page has started loading.
+  ///
+  /// See [PlatformWebViewController.setPlatformNavigationDelegate].
+  Future<void> setOnPageStarted(
+    void Function(String url) onPageStarted,
+  ) {
+    throw UnimplementedError(
+        'setOnPageStarted is not implemented on the current platform.');
+  }
+
+  /// Invoked when a page has finished loading.
+  ///
+  /// See [PlatformWebViewController.setPlatformNavigationDelegate].
+  Future<void> setOnPageFinished(
+    void Function(String url) onPageFinished,
+  ) {
+    throw UnimplementedError(
+        'setOnPageFinished is not implemented on the current platform.');
+  }
+
+  /// Invoked when a page is loading to report the progress.
+  ///
+  /// See [PlatformWebViewController.setPlatformNavigationDelegate].
+  Future<void> setOnProgress(
+    void Function(int progress) onProgress,
+  ) {
+    throw UnimplementedError(
+        'setOnProgress is not implemented on the current platform.');
+  }
+
+  /// Invoked when a resource loading error occurred.
+  ///
+  /// See [PlatformWebViewController.setPlatformNavigationDelegate].
+  Future<void> setOnWebResourceError(
+    void Function(WebResourceError error) onWebResourceError,
+  ) {
+    throw UnimplementedError(
+        'setOnWebResourceError is not implemented on the current platform.');
+  }
+}
diff --git a/packages/webview_flutter/webview_flutter_platform_interface/lib/v4/src/platform_webview_controller.dart b/packages/webview_flutter/webview_flutter_platform_interface/lib/v4/src/platform_webview_controller.dart
new file mode 100644
index 0000000..3585ec8
--- /dev/null
+++ b/packages/webview_flutter/webview_flutter_platform_interface/lib/v4/src/platform_webview_controller.dart
@@ -0,0 +1,285 @@
+// 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.
+
+import 'dart:math';
+import 'dart:ui';
+
+import 'package:flutter/foundation.dart';
+import 'package:plugin_platform_interface/plugin_platform_interface.dart';
+
+import 'platform_navigation_delegate.dart';
+import 'webview_platform.dart';
+
+/// Interface for a platform implementation of a web view controller.
+///
+/// Platform implementations should extend this class rather than implement it
+/// as `webview_flutter` does not consider newly added methods to be breaking
+/// changes. Extending this class (using `extends`) ensures that the subclass
+/// will get the default implementation, while platform implementations that
+/// `implements` this interface will be broken by newly added
+/// [PlatformWebViewCookieManager] methods.
+abstract class PlatformWebViewController extends PlatformInterface {
+  /// Creates a new [PlatformWebViewController]
+  factory PlatformWebViewController(
+      PlatformWebViewControllerCreationParams params) {
+    final PlatformWebViewController webViewControllerDelegate =
+        WebViewPlatform.instance!.createPlatformWebViewController(params);
+    PlatformInterface.verify(webViewControllerDelegate, _token);
+    return webViewControllerDelegate;
+  }
+
+  /// Used by the platform implementation to create a new [PlatformWebViewController].
+  ///
+  /// Should only be used by platform implementations because they can't extend
+  /// a class that only contains a factory constructor.
+  @protected
+  PlatformWebViewController.implementation(this.params) : super(token: _token);
+
+  static final Object _token = Object();
+
+  /// The parameters used to initialize the [PlatformWebViewController].
+  final PlatformWebViewControllerCreationParams params;
+
+  /// Loads the file located on the specified [absoluteFilePath].
+  ///
+  /// The [absoluteFilePath] parameter should contain the absolute path to the
+  /// file as it is stored on the device. For example:
+  /// `/Users/username/Documents/www/index.html`.
+  ///
+  /// Throws an ArgumentError if the [absoluteFilePath] does not exist.
+  Future<void> loadFile(
+    String absoluteFilePath,
+  ) {
+    throw UnimplementedError(
+        'loadFile is not implemented on the current platform');
+  }
+
+  /// Loads the Flutter asset specified in the pubspec.yaml file.
+  ///
+  /// Throws an ArgumentError if [key] is not part of the specified assets
+  /// in the pubspec.yaml file.
+  Future<void> loadFlutterAsset(
+    String key,
+  ) {
+    throw UnimplementedError(
+        'loadFlutterAsset is not implemented on the current platform');
+  }
+
+  /// Loads the supplied HTML string.
+  ///
+  /// The [baseUrl] parameter is used when resolving relative URLs within the
+  /// HTML string.
+  Future<void> loadHtmlString(
+    String html, {
+    String? baseUrl,
+  }) {
+    throw UnimplementedError(
+        'loadHtmlString is not implemented on the current platform');
+  }
+
+  /// Makes a specific HTTP request ands loads the response in the webview.
+  ///
+  /// [WebViewRequest.method] must be one of the supported HTTP methods
+  /// in [WebViewRequestMethod].
+  ///
+  /// If [WebViewRequest.headers] is not empty, its key-value pairs will be
+  /// added as the headers for the request.
+  ///
+  /// If [WebViewRequest.body] is not null, it will be added as the body
+  /// for the request.
+  ///
+  /// Throws an ArgumentError if [WebViewRequest.uri] has empty scheme.
+  Future<void> loadRequest(
+    LoadRequestParams params,
+  ) {
+    throw UnimplementedError(
+        'loadRequest is not implemented on the current platform');
+  }
+
+  /// Accessor to the current URL that the WebView is displaying.
+  ///
+  /// If no URL was ever loaded, returns `null`.
+  Future<String?> currentUrl() {
+    throw UnimplementedError(
+        'currentUrl is not implemented on the current platform');
+  }
+
+  /// Checks whether there's a back history item.
+  Future<bool> canGoBack() {
+    throw UnimplementedError(
+        'canGoBack is not implemented on the current platform');
+  }
+
+  /// Checks whether there's a forward history item.
+  Future<bool> canGoForward() {
+    throw UnimplementedError(
+        'canGoForward is not implemented on the current platform');
+  }
+
+  /// Goes back in the history of this WebView.
+  ///
+  /// If there is no back history item this is a no-op.
+  Future<void> goBack() {
+    throw UnimplementedError(
+        'goBack is not implemented on the current platform');
+  }
+
+  /// Goes forward in the history of this WebView.
+  ///
+  /// If there is no forward history item this is a no-op.
+  Future<void> goForward() {
+    throw UnimplementedError(
+        'goForward is not implemented on the current platform');
+  }
+
+  /// Reloads the current URL.
+  Future<void> reload() {
+    throw UnimplementedError(
+        'reload is not implemented on the current platform');
+  }
+
+  /// Clears all caches used by the [WebView].
+  ///
+  /// The following caches are cleared:
+  ///	1. Browser HTTP Cache.
+  ///	2. [Cache API](https://developers.google.com/web/fundamentals/instant-and-offline/web-storage/cache-api) caches.
+  ///    These are not yet supported in iOS WkWebView. Service workers tend to use this cache.
+  ///	3. Application cache.
+  Future<void> clearCache() {
+    throw UnimplementedError(
+        'clearCache is not implemented on the current platform');
+  }
+
+  /// Clears the local storage used by the [WebView].
+  Future<void> clearLocalStorage() {
+    throw UnimplementedError(
+        'clearLocalStorage is not implemented on the current platform');
+  }
+
+  /// Sets the [PlatformNavigationDelegate] containing the callback methods that
+  /// are called during navigation events.
+  Future<void> setPlatformNavigationDelegate(
+      PlatformNavigationDelegate handler) {
+    throw UnimplementedError(
+        'setPlatformNavigationDelegate is not implemented on the current platform');
+  }
+
+  /// Runs the given JavaScript in the context of the current page.
+  ///
+  /// The Future completes with an error if a JavaScript error occurred.
+  Future<void> runJavaScript(String javaScript) {
+    throw UnimplementedError(
+        'runJavaScript is not implemented on the current platform');
+  }
+
+  /// Runs the given JavaScript in the context of the current page, and returns the result.
+  ///
+  /// The Future completes with an error if a JavaScript error occurred, or if the
+  /// type the given expression evaluates to is unsupported. Unsupported values include
+  /// certain non-primitive types on iOS, as well as `undefined` or `null` on iOS 14+.
+  Future<String> runJavaScriptReturningResult(String javaScript) {
+    throw UnimplementedError(
+        'runJavaScriptReturningResult is not implemented on the current platform');
+  }
+
+  /// Adds a new JavaScript channel to the set of enabled channels.
+  Future<void> addJavaScriptChannel(
+    JavaScriptChannelParams javaScriptChannelParams,
+  ) {
+    throw UnimplementedError(
+        'addJavaScriptChannel is not implemented on the current platform');
+  }
+
+  /// Removes the JavaScript channel with the matching name from the set of
+  /// enabled channels.
+  ///
+  /// This disables the channel with the matching name if it was previously
+  /// enabled through the [addJavaScriptChannel].
+  Future<void> removeJavaScriptChannel(String javaScriptChannelName) {
+    throw UnimplementedError(
+        'removeJavaScriptChannel is not implemented on the current platform');
+  }
+
+  /// Returns the title of the currently loaded page.
+  Future<String?> getTitle() {
+    throw UnimplementedError(
+        'getTitle is not implemented on the current platform');
+  }
+
+  /// Set the scrolled position of this view.
+  ///
+  /// The parameters `x` and `y` specify the position to scroll to in WebView pixels.
+  Future<void> scrollTo(int x, int y) {
+    throw UnimplementedError(
+        'scrollTo is not implemented on the current platform');
+  }
+
+  /// Move the scrolled position of this view.
+  ///
+  /// The parameters `x` and `y` specify the amount of WebView pixels to scroll by.
+  Future<void> scrollBy(int x, int y) {
+    throw UnimplementedError(
+        'scrollBy is not implemented on the current platform');
+  }
+
+  /// Return the current scroll position of this view.
+  ///
+  /// Scroll position is measured from the top left.
+  Future<Point<int>> getScrollPosition() {
+    throw UnimplementedError(
+        'getScrollPosition is not implemented on the current platform');
+  }
+
+  /// Whether to enable the platform's webview content debugging tools.
+  Future<void> enableDebugging(bool enabled) {
+    throw UnimplementedError(
+        'enableDebugging is not implemented on the current platform');
+  }
+
+  /// Whether to allow swipe based navigation on supported platforms.
+  Future<void> enableGestureNavigation(bool enabled) {
+    throw UnimplementedError(
+        'enableGestureNavigation is not implemented on the current platform');
+  }
+
+  /// Whhether to support zooming using its on-screen zoom controls and gestures.
+  Future<void> enableZoom(bool enabled) {
+    throw UnimplementedError(
+        'enableZoom is not implemented on the current platform');
+  }
+
+  /// Set the current background color of this view.
+  Future<void> setBackgroundColor(Color color) {
+    throw UnimplementedError(
+        'setBackgroundColor is not implemented on the current platform');
+  }
+
+  /// Sets the JavaScript execution mode to be used by the webview.
+  Future<void> setJavaScriptMode(JavaScriptMode javaScriptMode) {
+    throw UnimplementedError(
+        'setJavaScriptMode is not implemented on the current platform');
+  }
+
+  /// Sets the value used for the HTTP `User-Agent:` request header.
+  Future<void> setUserAgent(String? userAgent) {
+    throw UnimplementedError(
+        'setUserAgent is not implemented on the current platform');
+  }
+}
+
+/// Describes the parameters necessary for registering a JavaScript channel.
+class JavaScriptChannelParams {
+  /// Creates a new [JavaScriptChannelParams] object.
+  JavaScriptChannelParams({
+    required this.name,
+    required this.onMessageReceived,
+  });
+
+  /// The name that identifies the JavaScript channel.
+  final String name;
+
+  /// The callback method that is invoked when a [JavaScriptMessage] is
+  /// received.
+  final void Function(JavaScriptMessage) onMessageReceived;
+}
diff --git a/packages/webview_flutter/webview_flutter_platform_interface/lib/v4/src/platform_webview_cookie_manager.dart b/packages/webview_flutter/webview_flutter_platform_interface/lib/v4/src/platform_webview_cookie_manager.dart
new file mode 100644
index 0000000..9e981c9
--- /dev/null
+++ b/packages/webview_flutter/webview_flutter_platform_interface/lib/v4/src/platform_webview_cookie_manager.dart
@@ -0,0 +1,55 @@
+// 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.
+
+import 'package:flutter/foundation.dart';
+import 'package:plugin_platform_interface/plugin_platform_interface.dart';
+
+import 'webview_platform.dart';
+
+/// Interface for a platform implementation of a cookie manager.
+///
+/// Platform implementations should extend this class rather than implement it
+/// as `webview_flutter` does not consider newly added methods to be breaking
+/// changes. Extending this class (using `extends`) ensures that the subclass
+/// will get the default implementation, while platform implementations that
+/// `implements` this interface will be broken by newly added
+/// [PlatformWebViewCookieManager] methods.
+abstract class PlatformWebViewCookieManager extends PlatformInterface {
+  /// Creates a new [PlatformWebViewCookieManager]
+  factory PlatformWebViewCookieManager(
+      PlatformWebViewCookieManagerCreationParams params) {
+    final PlatformWebViewCookieManager cookieManagerDelegate =
+        WebViewPlatform.instance!.createPlatformCookieManager(params);
+    PlatformInterface.verify(cookieManagerDelegate, _token);
+    return cookieManagerDelegate;
+  }
+
+  /// Used by the platform implementation to create a new
+  /// [PlatformWebViewCookieManager].
+  ///
+  /// Should only be used by platform implementations because they can't extend
+  /// a class that only contains a factory constructor.
+  @protected
+  PlatformWebViewCookieManager.implementation(this.params)
+      : super(token: _token);
+
+  static final Object _token = Object();
+
+  /// The parameters used to initialize the [PlatformWebViewCookieManager].
+  final PlatformWebViewCookieManagerCreationParams params;
+
+  /// Clears all cookies for all [WebView] instances.
+  ///
+  /// Returns true if cookies were present before clearing, else false.
+  Future<bool> clearCookies() {
+    throw UnimplementedError(
+        'clearCookies is not implemented on the current platform');
+  }
+
+  /// Sets a cookie for all [WebView] instances.
+  Future<void> setCookie(WebViewCookie cookie) {
+    throw UnimplementedError(
+        'setCookie is not implemented on the current platform');
+  }
+}
diff --git a/packages/webview_flutter/webview_flutter_platform_interface/lib/v4/src/platform_webview_widget.dart b/packages/webview_flutter/webview_flutter_platform_interface/lib/v4/src/platform_webview_widget.dart
new file mode 100644
index 0000000..40334c6
--- /dev/null
+++ b/packages/webview_flutter/webview_flutter_platform_interface/lib/v4/src/platform_webview_widget.dart
@@ -0,0 +1,37 @@
+// 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.
+
+import 'package:flutter/widgets.dart';
+import 'package:plugin_platform_interface/plugin_platform_interface.dart';
+
+import 'webview_platform.dart';
+
+/// Interface for a platform implementation of a web view widget.
+abstract class PlatformWebViewWidget extends PlatformInterface {
+  /// Creates a new [PlatformWebViewWidget]
+  factory PlatformWebViewWidget(PlatformWebViewWidgetCreationParams params) {
+    final PlatformWebViewWidget webViewWidgetDelegate =
+        WebViewPlatform.instance!.createPlatformWebViewWidget(params);
+    PlatformInterface.verify(webViewWidgetDelegate, _token);
+    return webViewWidgetDelegate;
+  }
+
+  /// Used by the platform implementation to create a new
+  /// [PlatformWebViewWidget].
+  ///
+  /// Should only be used by platform implementations because they can't extend
+  /// a class that only contains a factory constructor.
+  @protected
+  PlatformWebViewWidget.implementation(this.params) : super(token: _token);
+
+  static final Object _token = Object();
+
+  /// The parameters used to initialize the [PlatformWebViewWidget].
+  final PlatformWebViewWidgetCreationParams params;
+
+  /// Builds a new WebView.
+  ///
+  /// Returns a Widget tree that embeds the created web view.
+  Widget build(BuildContext context);
+}
diff --git a/packages/webview_flutter/webview_flutter_platform_interface/lib/v4/src/types/javascript_message.dart b/packages/webview_flutter/webview_flutter_platform_interface/lib/v4/src/types/javascript_message.dart
new file mode 100644
index 0000000..b37661a
--- /dev/null
+++ b/packages/webview_flutter/webview_flutter_platform_interface/lib/v4/src/types/javascript_message.dart
@@ -0,0 +1,51 @@
+// 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.
+
+import 'package:flutter/foundation.dart';
+
+/// A message that was sent by JavaScript code running in a [WebView].
+///
+/// Platform specific implementations can add additional fields by extending
+/// this class and providing a factory method that takes the
+/// [JavaScriptMessage] as a parameter.
+///
+/// {@tool sample}
+/// This example demonstrates how to extend the [JavaScriptMessage] to
+/// provide additional platform specific parameters.
+///
+/// When extending [JavaScriptMessage] additional parameters should always
+/// accept `null` or have a default value to prevent breaking changes.
+///
+/// ```dart
+/// @immutable
+/// class WKWebViewScriptMessage extends JavaScriptMessage {
+///   WKWebViewScriptMessage._(
+///     JavaScriptMessage javaScriptMessage,
+///     this.extraData,
+///   ) : super(javaScriptMessage.message);
+///
+///   factory WKWebViewScriptMessage.fromJavaScripMessage(
+///     JavaScriptMessage javaScripMessage, {
+///     String? extraData,
+///   }) {
+///     return WKWebViewScriptMessage._(
+///       javaScriptMessage,
+///       extraData: extraData,
+///     );
+///   }
+///
+///   final String? extraData;
+/// }
+/// ```
+/// {@end-tool}
+@immutable
+class JavaScriptMessage {
+  /// Creates a new JavaScript message object.
+  const JavaScriptMessage({
+    required this.message,
+  });
+
+  /// The contents of the message that was sent by the JavaScript code.
+  final String message;
+}
diff --git a/packages/webview_flutter/webview_flutter_platform_interface/lib/v4/src/types/javascript_mode.dart b/packages/webview_flutter/webview_flutter_platform_interface/lib/v4/src/types/javascript_mode.dart
new file mode 100644
index 0000000..bcbebff
--- /dev/null
+++ b/packages/webview_flutter/webview_flutter_platform_interface/lib/v4/src/types/javascript_mode.dart
@@ -0,0 +1,12 @@
+// 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.
+
+/// Describes the state of JavaScript support in a given web view.
+enum JavaScriptMode {
+  /// JavaScript execution is disabled.
+  disabled,
+
+  /// JavaScript execution is not restricted.
+  unrestricted,
+}
diff --git a/packages/webview_flutter/webview_flutter_platform_interface/lib/v4/src/types/load_request_params.dart b/packages/webview_flutter/webview_flutter_platform_interface/lib/v4/src/types/load_request_params.dart
new file mode 100644
index 0000000..2da51f8
--- /dev/null
+++ b/packages/webview_flutter/webview_flutter_platform_interface/lib/v4/src/types/load_request_params.dart
@@ -0,0 +1,89 @@
+// 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.
+
+import 'dart:typed_data';
+
+import 'package:flutter/foundation.dart';
+
+import '../platform_webview_controller.dart';
+
+/// Defines the supported HTTP methods for loading a page in [PlatformWebViewController].
+enum LoadRequestMethod {
+  /// HTTP GET method.
+  get,
+
+  /// HTTP POST method.
+  post,
+}
+
+/// Extension methods on the [LoadRequestMethod] enum.
+extension LoadRequestMethodExtensions on LoadRequestMethod {
+  /// Converts [LoadRequestMethod] to [String] format.
+  String serialize() {
+    switch (this) {
+      case LoadRequestMethod.get:
+        return 'get';
+      case LoadRequestMethod.post:
+        return 'post';
+    }
+  }
+}
+
+/// Defines the parameters that can be used to load a page with the [PlatformWebViewController].
+///
+/// Platform specific implementations can add additional fields by extending
+/// this class.
+///
+/// {@tool sample}
+/// This example demonstrates how to extend the [LoadRequestParams] to
+/// provide additional platform specific parameters.
+///
+/// When extending [LoadRequestParams] additional parameters should always
+/// accept `null` or have a default value to prevent breaking changes.
+///
+/// ```dart
+/// class AndroidLoadRequestParams extends LoadRequestParams {
+///   AndroidLoadRequestParams._({
+///     required LoadRequestParams params,
+///     this.historyUrl,
+///   }) : super(
+///     uri: params.uri,
+///     method: params.method,
+///     body: params.body,
+///     headers: params.headers,
+///   );
+///
+///   factory AndroidLoadRequestParams.fromLoadRequestParams(
+///     LoadRequestParams params, {
+///     Uri? historyUrl,
+///   }) {
+///     return AndroidLoadRequestParams._(params, historyUrl: historyUrl);
+///   }
+///
+///   final Uri? historyUrl;
+/// }
+/// ```
+/// {@end-tool}
+@immutable
+class LoadRequestParams {
+  /// Used by the platform implementation to create a new [LoadRequestParams].
+  const LoadRequestParams({
+    required this.uri,
+    required this.method,
+    required this.headers,
+    this.body,
+  });
+
+  /// URI for the request.
+  final Uri uri;
+
+  /// HTTP method used to make the request.
+  final LoadRequestMethod method;
+
+  /// Headers for the request.
+  final Map<String, String> headers;
+
+  /// HTTP body for the request.
+  final Uint8List? body;
+}
diff --git a/packages/webview_flutter/webview_flutter_platform_interface/lib/v4/src/types/platform_navigation_delegate_creation_params.dart b/packages/webview_flutter/webview_flutter_platform_interface/lib/v4/src/types/platform_navigation_delegate_creation_params.dart
new file mode 100644
index 0000000..b20e5eb
--- /dev/null
+++ b/packages/webview_flutter/webview_flutter_platform_interface/lib/v4/src/types/platform_navigation_delegate_creation_params.dart
@@ -0,0 +1,44 @@
+// 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.
+
+import 'package:flutter/material.dart';
+
+/// Object specifying creation parameters for creating a [PlatformNavigationDelegate].
+///
+/// Platform specific implementations can add additional fields by extending
+/// this class.
+///
+/// {@tool sample}
+/// This example demonstrates how to extend the [PlatformNavigationDelegateCreationParams] to
+/// provide additional platform specific parameters.
+///
+/// When extending [PlatformNavigationDelegateCreationParams] additional
+/// parameters should always accept `null` or have a default value to prevent
+/// breaking changes.
+///
+/// ```dart
+/// class AndroidNavigationDelegateCreationParams extends PlatformNavigationDelegateCreationParams {
+///   AndroidNavigationDelegateCreationParams._(
+///     // This parameter prevents breaking changes later.
+///     // ignore: avoid_unused_constructor_parameters
+///     PlatformNavigationDelegateCreationParams params, {
+///     this.filter,
+///   }) : super();
+///
+///   factory AndroidNavigationDelegateCreationParams.fromPlatformNavigationDelegateCreationParams(
+///       PlatformNavigationDelegateCreationParams params, {
+///       String? filter,
+///   }) {
+///     return AndroidNavigationDelegateCreationParams._(params, filter: filter);
+///   }
+///
+///   final String? filter;
+/// }
+/// ```
+/// {@end-tool}
+@immutable
+class PlatformNavigationDelegateCreationParams {
+  /// Used by the platform implementation to create a new [PlatformNavigationkDelegate].
+  const PlatformNavigationDelegateCreationParams();
+}
diff --git a/packages/webview_flutter/webview_flutter_platform_interface/lib/v4/src/types/platform_webview_controller_creation_params.dart b/packages/webview_flutter/webview_flutter_platform_interface/lib/v4/src/types/platform_webview_controller_creation_params.dart
new file mode 100644
index 0000000..778396a
--- /dev/null
+++ b/packages/webview_flutter/webview_flutter_platform_interface/lib/v4/src/types/platform_webview_controller_creation_params.dart
@@ -0,0 +1,45 @@
+// 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.
+
+import 'package:flutter/material.dart';
+
+/// Object specifying creation parameters for creating a [PlatformWebViewController].
+///
+/// Platform specific implementations can add additional fields by extending
+/// this class.
+///
+/// {@tool sample}
+/// This example demonstrates how to extend the [PlatformWebViewControllerCreationParams] to
+/// provide additional platform specific parameters.
+///
+/// When extending [PlatformWebViewControllerCreationParams] additional parameters
+/// should always accept `null` or have a default value to prevent breaking
+/// changes.
+///
+/// ```dart
+/// class WKWebViewControllerCreationParams
+///     extends PlatformWebViewControllerCreationParams {
+///   WKWebViewControllerCreationParams._(
+///     // This parameter prevents breaking changes later.
+///     // ignore: avoid_unused_constructor_parameters
+///     PlatformWebViewControllerCreationParams params, {
+///     this.domain,
+///   }) : super();
+///
+///   factory WKWebViewControllerCreationParams.fromPlatformWebViewControllerCreationParams(
+///     PlatformWebViewControllerCreationParams params, {
+///     String? domain,
+///   }) {
+///     return WKWebViewControllerCreationParams._(params, domain: domain);
+///   }
+///
+///   final String? domain;
+/// }
+/// ```
+/// {@end-tool}
+@immutable
+class PlatformWebViewControllerCreationParams {
+  /// Used by the platform implementation to create a new [PlatformWebViewController].
+  const PlatformWebViewControllerCreationParams();
+}
diff --git a/packages/webview_flutter/webview_flutter_platform_interface/lib/v4/src/types/platform_webview_cookie_manager_creation_params.dart b/packages/webview_flutter/webview_flutter_platform_interface/lib/v4/src/types/platform_webview_cookie_manager_creation_params.dart
new file mode 100644
index 0000000..e8c4938
--- /dev/null
+++ b/packages/webview_flutter/webview_flutter_platform_interface/lib/v4/src/types/platform_webview_cookie_manager_creation_params.dart
@@ -0,0 +1,45 @@
+// 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.
+
+import 'package:flutter/material.dart';
+
+/// Object specifying creation parameters for creating a [PlatformWebViewCookieManager].
+///
+/// Platform specific implementations can add additional fields by extending
+/// this class.
+///
+/// {@tool sample}
+/// This example demonstrates how to extend the [PlatformWebViewCookieManagerCreationParams] to
+/// provide additional platform specific parameters.
+///
+/// When extending [PlatformWebViewCookieManagerCreationParams] additional
+/// parameters should always accept `null` or have a default value to prevent
+/// breaking changes.
+///
+/// ```dart
+/// class WKWebViewCookieManagerCreationParams
+///     extends PlatformWebViewCookieManagerCreationParams {
+///   WKWebViewCookieManagerCreationParams._(
+///     // This parameter prevents breaking changes later.
+///     // ignore: avoid_unused_constructor_parameters
+///     PlatformWebViewCookieManagerCreationParams params, {
+///     this.uri,
+///   }) : super();
+///
+///   factory WKWebViewCookieManagerCreationParams.fromPlatformWebViewCookieManagerCreationParams(
+///     PlatformWebViewCookieManagerCreationParams params, {
+///     Uri? uri,
+///   }) {
+///     return WKWebViewCookieManagerCreationParams._(params, uri: uri);
+///   }
+///
+///   final Uri? uri;
+/// }
+/// ```
+/// {@end-tool}
+@immutable
+class PlatformWebViewCookieManagerCreationParams {
+  /// Used by the platform implementation to create a new [PlatformWebViewCookieManagerDelegate].
+  const PlatformWebViewCookieManagerCreationParams();
+}
diff --git a/packages/webview_flutter/webview_flutter_platform_interface/lib/v4/src/types/platform_webview_widget_creation_params.dart b/packages/webview_flutter/webview_flutter_platform_interface/lib/v4/src/types/platform_webview_widget_creation_params.dart
new file mode 100644
index 0000000..1812d7e
--- /dev/null
+++ b/packages/webview_flutter/webview_flutter_platform_interface/lib/v4/src/types/platform_webview_widget_creation_params.dart
@@ -0,0 +1,79 @@
+// 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.
+
+import 'package:flutter/foundation.dart';
+import 'package:flutter/gestures.dart';
+
+import '../platform_webview_controller.dart';
+
+/// Object specifying creation parameters for creating a [WebViewWidgetDelegate].
+///
+/// Platform specific implementations can add additional fields by extending
+/// this class.
+///
+/// {@tool sample}
+/// This example demonstrates how to extend the [PlatformWebViewWidgetCreationParams] to
+/// provide additional platform specific parameters.
+///
+/// When extending [PlatformWebViewWidgetCreationParams] additional parameters
+/// should always accept `null` or have a default value to prevent breaking
+/// changes.
+///
+/// ```dart
+/// class WKWebViewWidgetCreationParams extends PlatformWebViewWidgetCreationParams {
+///   WKWebViewWidgetCreationParams._(
+///     // This parameter prevents breaking changes later.
+///     // ignore: avoid_unused_constructor_parameters
+///     PlatformWebViewWidgetCreationParams params, {
+///     this.domain,
+///   }) : super(
+///           key: params.key,
+///           controller: params.controller,
+///           gestureRecognizers: params.gestureRecognizers,
+///         );
+///
+///   factory WKWebViewWidgetCreationParams.fromPlatformWebViewWidgetCreationParams(
+///     PlatformWebViewWidgetCreationParams params, {
+///     String? domain,
+///   }) {
+///     return WKWebViewWidgetCreationParams._(params, domain: domain);
+///   }
+///
+///   final String? domain;
+/// }
+/// ```
+/// {@end-tool}
+@immutable
+class PlatformWebViewWidgetCreationParams {
+  /// Used by the platform implementation to create a new [PlatformWebViewWidget].
+  const PlatformWebViewWidgetCreationParams({
+    this.key,
+    required this.controller,
+    this.gestureRecognizers = const <Factory<OneSequenceGestureRecognizer>>{},
+  });
+
+  /// Controls how one widget replaces another widget in the tree.
+  ///
+  /// See also:
+  ///
+  ///  * The discussions at [Key] and [GlobalKey].
+  final Key? key;
+
+  /// The [PlatformWebViewController] that allows controlling the native web
+  /// view.
+  final PlatformWebViewController controller;
+
+  /// The `gestureRecognizers` specifies which gestures should be consumed by the
+  /// web view.
+  ///
+  /// It is possible for other gesture recognizers to be competing with the web
+  /// view on pointer events, e.g if the web view is inside a [ListView] the
+  /// [ListView] will want to handle vertical drags. The web view will claim
+  /// gestures that are recognized by any of the recognizers on this list.
+  ///
+  /// When `gestureRecognizers` is empty (default), the web view will only handle
+  /// pointer events for gestures that were not claimed by any other gesture
+  /// recognizer.
+  final Set<Factory<OneSequenceGestureRecognizer>> gestureRecognizers;
+}
diff --git a/packages/webview_flutter/webview_flutter_platform_interface/lib/v4/src/types/types.dart b/packages/webview_flutter/webview_flutter_platform_interface/lib/v4/src/types/types.dart
new file mode 100644
index 0000000..05504ff
--- /dev/null
+++ b/packages/webview_flutter/webview_flutter_platform_interface/lib/v4/src/types/types.dart
@@ -0,0 +1,13 @@
+// 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 'javascript_message.dart';
+export 'javascript_mode.dart';
+export 'load_request_params.dart';
+export 'platform_navigation_delegate_creation_params.dart';
+export 'platform_webview_controller_creation_params.dart';
+export 'platform_webview_cookie_manager_creation_params.dart';
+export 'platform_webview_widget_creation_params.dart';
+export 'web_resource_error.dart';
+export 'webview_cookie.dart';
diff --git a/packages/webview_flutter/webview_flutter_platform_interface/lib/v4/src/types/web_resource_error.dart b/packages/webview_flutter/webview_flutter_platform_interface/lib/v4/src/types/web_resource_error.dart
new file mode 100644
index 0000000..4657994
--- /dev/null
+++ b/packages/webview_flutter/webview_flutter_platform_interface/lib/v4/src/types/web_resource_error.dart
@@ -0,0 +1,119 @@
+// 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.
+
+import 'package:flutter/foundation.dart';
+
+/// Possible error type categorizations used by [WebResourceError].
+enum WebResourceErrorType {
+  /// User authentication failed on server.
+  authentication,
+
+  /// Malformed URL.
+  badUrl,
+
+  /// Failed to connect to the server.
+  connect,
+
+  /// Failed to perform SSL handshake.
+  failedSslHandshake,
+
+  /// Generic file error.
+  file,
+
+  /// File not found.
+  fileNotFound,
+
+  /// Server or proxy hostname lookup failed.
+  hostLookup,
+
+  /// Failed to read or write to the server.
+  io,
+
+  /// User authentication failed on proxy.
+  proxyAuthentication,
+
+  /// Too many redirects.
+  redirectLoop,
+
+  /// Connection timed out.
+  timeout,
+
+  /// Too many requests during this load.
+  tooManyRequests,
+
+  /// Generic error.
+  unknown,
+
+  /// Resource load was canceled by Safe Browsing.
+  unsafeResource,
+
+  /// Unsupported authentication scheme (not basic or digest).
+  unsupportedAuthScheme,
+
+  /// Unsupported URI scheme.
+  unsupportedScheme,
+
+  /// The web content process was terminated.
+  webContentProcessTerminated,
+
+  /// The web view was invalidated.
+  webViewInvalidated,
+
+  /// A JavaScript exception occurred.
+  javaScriptExceptionOccurred,
+
+  /// The result of JavaScript execution could not be returned.
+  javaScriptResultTypeIsUnsupported,
+}
+
+/// Error returned in `WebView.onWebResourceError` when a web resource loading error has occurred.
+///
+/// Platform specific implementations can add additional fields by extending
+/// this class.
+///
+/// {@tool sample}
+/// This example demonstrates how to extend the [WebResourceError] to
+/// provide additional platform specific parameters.
+///
+/// When extending [WebResourceError] additional parameters should always
+/// accept `null` or have a default value to prevent breaking changes.
+///
+/// ```dart
+/// class IOSWebResourceError extends WebResourceError {
+///   IOSWebResourceError._(WebResourceError error, {required this.domain})
+///       : super(
+///           errorCode: error.errorCode,
+///           description: error.description,
+///           errorType: error.errorType,
+///         );
+///
+///   factory IOSWebResourceError.fromWebResourceError(
+///     WebResourceError error, {
+///     required String? domain,
+///   }) {
+///     return IOSWebResourceError._(error, domain: domain);
+///   }
+///
+///   final String? domain;
+/// }
+/// ```
+/// {@end-tool}
+@immutable
+class WebResourceError {
+  /// Used by the platform implementation to create a new [WebResourceError].
+  const WebResourceError({
+    required this.errorCode,
+    required this.description,
+    this.errorType,
+  });
+
+  /// Raw code of the error from the respective platform.
+  final int errorCode;
+
+  /// Description of the error that can be used to communicate the problem to the user.
+  final String description;
+
+  /// The type this error can be categorized as.
+  final WebResourceErrorType? errorType;
+}
diff --git a/packages/webview_flutter/webview_flutter_platform_interface/lib/v4/src/types/webview_cookie.dart b/packages/webview_flutter/webview_flutter_platform_interface/lib/v4/src/types/webview_cookie.dart
new file mode 100644
index 0000000..7f56a31
--- /dev/null
+++ b/packages/webview_flutter/webview_flutter_platform_interface/lib/v4/src/types/webview_cookie.dart
@@ -0,0 +1,41 @@
+// 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.
+
+import 'package:flutter/foundation.dart';
+
+/// A cookie that can be set globally for all web views using [WebViewCookieManagerPlatform].
+@immutable
+class WebViewCookie {
+  /// Creates a new [WebViewCookieDelegate]
+  const WebViewCookie({
+    required this.name,
+    required this.value,
+    required this.domain,
+    this.path = '/',
+  });
+
+  /// The cookie-name of the cookie.
+  ///
+  /// Its value should match "cookie-name" in RFC6265bis:
+  /// https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-rfc6265bis-02#section-4.1.1
+  final String name;
+
+  /// The cookie-value of the cookie.
+  ///
+  /// Its value should match "cookie-value" in RFC6265bis:
+  /// https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-rfc6265bis-02#section-4.1.1
+  final String value;
+
+  /// The domain-value of the cookie.
+  ///
+  /// Its value should match "domain-value" in RFC6265bis:
+  /// https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-rfc6265bis-02#section-4.1.1
+  final String domain;
+
+  /// The path-value of the cookie, set to `/` by default.
+  ///
+  /// Its value should match "path-value" in RFC6265bis:
+  /// https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-rfc6265bis-02#section-4.1.1
+  final String path;
+}
diff --git a/packages/webview_flutter/webview_flutter_platform_interface/lib/v4/src/webview_platform.dart b/packages/webview_flutter/webview_flutter_platform_interface/lib/v4/src/webview_platform.dart
new file mode 100644
index 0000000..c5c5dff
--- /dev/null
+++ b/packages/webview_flutter/webview_flutter_platform_interface/lib/v4/src/webview_platform.dart
@@ -0,0 +1,82 @@
+// 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.
+
+import 'package:plugin_platform_interface/plugin_platform_interface.dart';
+
+import 'platform_navigation_delegate.dart';
+import 'platform_webview_controller.dart';
+import 'platform_webview_cookie_manager.dart';
+import 'platform_webview_widget.dart';
+import 'types/types.dart';
+
+export 'types/types.dart';
+
+/// Interface for a platform implementation of a WebView.
+abstract class WebViewPlatform extends PlatformInterface {
+  /// Creates a new [WebViewPlatform].
+  WebViewPlatform() : super(token: _token);
+
+  static final Object _token = Object();
+
+  static WebViewPlatform? _instance;
+
+  /// The instance of [WebViewPlatform] to use.
+  static WebViewPlatform? get instance => _instance;
+
+  /// Platform-specific plugins should set this with their own platform-specific
+  /// class that extends [WebViewPlatform] when they register themselves.
+  static set instance(WebViewPlatform? instance) {
+    if (instance == null) {
+      throw AssertionError(
+          'Platform interfaces can only be set to a non-null instance');
+    }
+
+    PlatformInterface.verify(instance, _token);
+    _instance = instance;
+  }
+
+  /// Creates a new [PlatformWebViewCookieManager].
+  ///
+  /// This function should only be called by the app-facing package.
+  /// Look at using [WebViewCookieManager] in `webview_flutter` instead.
+  PlatformWebViewCookieManager createPlatformCookieManager(
+    PlatformWebViewCookieManagerCreationParams params,
+  ) {
+    throw UnimplementedError(
+        'createPlatformCookieManager is not implemented on the current platform.');
+  }
+
+  /// Creates a new [PlatformNavigationDelegate].
+  ///
+  /// This function should only be called by the app-facing package.
+  /// Look at using [NavigationDelegate] in `webview_flutter` instead.
+  PlatformNavigationDelegate createPlatformNavigationDelegate(
+    PlatformNavigationDelegateCreationParams params,
+  ) {
+    throw UnimplementedError(
+        'createPlatformNavigationDelegate is not implemented on the current platform.');
+  }
+
+  /// Create a new [PlatformWebViewController].
+  ///
+  /// This function should only be called by the app-facing package.
+  /// Look at using [WebViewController] in `webview_flutter` instead.
+  PlatformWebViewController createPlatformWebViewController(
+    PlatformWebViewControllerCreationParams params,
+  ) {
+    throw UnimplementedError(
+        'createPlatformWebViewController is not implemented on the current platform.');
+  }
+
+  /// Create a new [PlatformWebViewWidget].
+  ///
+  /// This function should only be called by the app-facing package.
+  /// Look at using [WebViewWidget] in `webview_flutter` instead.
+  PlatformWebViewWidget createPlatformWebViewWidget(
+    PlatformWebViewWidgetCreationParams params,
+  ) {
+    throw UnimplementedError(
+        'createPlatformWebViewWidget is not implemented on the current platform.');
+  }
+}
diff --git a/packages/webview_flutter/webview_flutter_platform_interface/lib/v4/webview_flutter_platform_interface.dart b/packages/webview_flutter/webview_flutter_platform_interface/lib/v4/webview_flutter_platform_interface.dart
new file mode 100644
index 0000000..d14fec1
--- /dev/null
+++ b/packages/webview_flutter/webview_flutter_platform_interface/lib/v4/webview_flutter_platform_interface.dart
@@ -0,0 +1,10 @@
+// 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 'src/platform_navigation_delegate.dart';
+export 'src/platform_webview_controller.dart';
+export 'src/platform_webview_cookie_manager.dart';
+export 'src/platform_webview_widget.dart';
+export 'src/types/types.dart';
+export 'src/webview_platform.dart';
diff --git a/packages/webview_flutter/webview_flutter_platform_interface/pubspec.yaml b/packages/webview_flutter/webview_flutter_platform_interface/pubspec.yaml
index f9e7549..c339a0f 100644
--- a/packages/webview_flutter/webview_flutter_platform_interface/pubspec.yaml
+++ b/packages/webview_flutter/webview_flutter_platform_interface/pubspec.yaml
@@ -4,7 +4,7 @@
 issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+webview_flutter%22
 # NOTE: We strongly prefer non-breaking changes, even at the expense of a
 # less-clean API. See https://flutter.dev/go/platform-interface-breaking-changes
-version: 1.8.2
+version: 1.9.0
 
 environment:
   sdk: ">=2.12.0 <3.0.0"
@@ -13,9 +13,11 @@
 dependencies:
   flutter:
     sdk: flutter
+  meta: ^1.7.0
   plugin_platform_interface: ^2.1.0
 
 dev_dependencies:
+  build_runner: ^2.1.8
   flutter_test:
     sdk: flutter
   mockito: ^5.0.0
diff --git a/packages/webview_flutter/webview_flutter_platform_interface/test/src/v4/platform_navigation_delegate_test.dart b/packages/webview_flutter/webview_flutter_platform_interface/test/src/v4/platform_navigation_delegate_test.dart
new file mode 100644
index 0000000..5674c15
--- /dev/null
+++ b/packages/webview_flutter/webview_flutter_platform_interface/test/src/v4/platform_navigation_delegate_test.dart
@@ -0,0 +1,141 @@
+// 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.
+
+import 'package:flutter_test/flutter_test.dart';
+import 'package:mockito/mockito.dart';
+import 'package:plugin_platform_interface/plugin_platform_interface.dart';
+import 'package:webview_flutter_platform_interface/v4/src/platform_navigation_delegate.dart';
+import 'package:webview_flutter_platform_interface/v4/src/webview_platform.dart';
+
+import 'webview_platform_test.mocks.dart';
+
+void main() {
+  setUp(() {
+    WebViewPlatform.instance = MockWebViewPlatformWithMixin();
+  });
+
+  test('Cannot be implemented with `implements`', () {
+    const PlatformNavigationDelegateCreationParams params =
+        PlatformNavigationDelegateCreationParams();
+    when(WebViewPlatform.instance!.createPlatformNavigationDelegate(params))
+        .thenReturn(ImplementsPlatformNavigationDelegate());
+
+    expect(() {
+      PlatformNavigationDelegate(params);
+    }, throwsNoSuchMethodError);
+  });
+
+  test('Can be extended', () {
+    const PlatformNavigationDelegateCreationParams params =
+        PlatformNavigationDelegateCreationParams();
+    when(WebViewPlatform.instance!.createPlatformNavigationDelegate(params))
+        .thenReturn(ExtendsPlatformNavigationDelegate(params));
+
+    expect(PlatformNavigationDelegate(params), isNotNull);
+  });
+
+  test('Can be mocked with `implements`', () {
+    const PlatformNavigationDelegateCreationParams params =
+        PlatformNavigationDelegateCreationParams();
+    when(WebViewPlatform.instance!.createPlatformNavigationDelegate(params))
+        .thenReturn(MockNavigationDelegate());
+
+    expect(PlatformNavigationDelegate(params), isNotNull);
+  });
+
+  test(
+      // ignore: lines_longer_than_80_chars
+      'Default implementation of setOnNavigationRequest should throw unimplemented error',
+      () {
+    final PlatformNavigationDelegate callbackDelegate =
+        ExtendsPlatformNavigationDelegate(
+            const PlatformNavigationDelegateCreationParams());
+
+    expect(
+      () => callbackDelegate.setOnNavigationRequest(
+          ({required bool isForMainFrame, required String url}) => true),
+      throwsUnimplementedError,
+    );
+  });
+
+  test(
+      // ignore: lines_longer_than_80_chars
+      'Default implementation of setOnPageStarted should throw unimplemented error',
+      () {
+    final PlatformNavigationDelegate callbackDelegate =
+        ExtendsPlatformNavigationDelegate(
+            const PlatformNavigationDelegateCreationParams());
+
+    expect(
+      () => callbackDelegate.setOnPageStarted((String url) {}),
+      throwsUnimplementedError,
+    );
+  });
+
+  test(
+      // ignore: lines_longer_than_80_chars
+      'Default implementation of setOnPageFinished should throw unimplemented error',
+      () {
+    final PlatformNavigationDelegate callbackDelegate =
+        ExtendsPlatformNavigationDelegate(
+            const PlatformNavigationDelegateCreationParams());
+
+    expect(
+      () => callbackDelegate.setOnPageFinished((String url) {}),
+      throwsUnimplementedError,
+    );
+  });
+
+  test(
+      // ignore: lines_longer_than_80_chars
+      'Default implementation of setOnProgress should throw unimplemented error',
+      () {
+    final PlatformNavigationDelegate callbackDelegate =
+        ExtendsPlatformNavigationDelegate(
+            const PlatformNavigationDelegateCreationParams());
+
+    expect(
+      () => callbackDelegate.setOnProgress((int progress) {}),
+      throwsUnimplementedError,
+    );
+  });
+
+  test(
+      // ignore: lines_longer_than_80_chars
+      'Default implementation of setOnWebResourceError should throw unimplemented error',
+      () {
+    final PlatformNavigationDelegate callbackDelegate =
+        ExtendsPlatformNavigationDelegate(
+            const PlatformNavigationDelegateCreationParams());
+
+    expect(
+      () => callbackDelegate.setOnWebResourceError((WebResourceError error) {}),
+      throwsUnimplementedError,
+    );
+  });
+}
+
+class MockWebViewPlatformWithMixin extends MockWebViewPlatform
+    with
+        // ignore: prefer_mixin
+        MockPlatformInterfaceMixin {}
+
+class ImplementsPlatformNavigationDelegate
+    implements PlatformNavigationDelegate {
+  @override
+  dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+}
+
+class MockNavigationDelegate extends Mock
+    with
+        // ignore: prefer_mixin
+        MockPlatformInterfaceMixin
+    implements
+        PlatformNavigationDelegate {}
+
+class ExtendsPlatformNavigationDelegate extends PlatformNavigationDelegate {
+  ExtendsPlatformNavigationDelegate(
+      PlatformNavigationDelegateCreationParams params)
+      : super.implementation(params);
+}
diff --git a/packages/webview_flutter/webview_flutter_platform_interface/test/src/v4/platform_webview_controller_test.dart b/packages/webview_flutter/webview_flutter_platform_interface/test/src/v4/platform_webview_controller_test.dart
new file mode 100644
index 0000000..b6d043c
--- /dev/null
+++ b/packages/webview_flutter/webview_flutter_platform_interface/test/src/v4/platform_webview_controller_test.dart
@@ -0,0 +1,467 @@
+// 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.
+
+import 'package:flutter/material.dart';
+import 'package:flutter_test/flutter_test.dart';
+import 'package:mockito/annotations.dart';
+import 'package:mockito/mockito.dart';
+import 'package:plugin_platform_interface/plugin_platform_interface.dart';
+import 'package:webview_flutter_platform_interface/v4/src/platform_navigation_delegate.dart';
+import 'package:webview_flutter_platform_interface/v4/src/platform_webview_controller.dart';
+import 'package:webview_flutter_platform_interface/v4/src/webview_platform.dart';
+
+import 'platform_navigation_delegate_test.dart';
+import 'webview_platform_test.mocks.dart';
+
+@GenerateMocks(<Type>[PlatformNavigationDelegate])
+void main() {
+  setUp(() {
+    WebViewPlatform.instance = MockWebViewPlatformWithMixin();
+  });
+
+  test('Cannot be implemented with `implements`', () {
+    when((WebViewPlatform.instance! as MockWebViewPlatform)
+            .createPlatformWebViewController(any))
+        .thenReturn(ImplementsPlatformWebViewController());
+
+    expect(() {
+      PlatformWebViewController(
+          const PlatformWebViewControllerCreationParams());
+    }, throwsNoSuchMethodError);
+  });
+
+  test('Can be extended', () {
+    const PlatformWebViewControllerCreationParams params =
+        PlatformWebViewControllerCreationParams();
+    when((WebViewPlatform.instance! as MockWebViewPlatform)
+            .createPlatformWebViewController(any))
+        .thenReturn(ExtendsPlatformWebViewController(params));
+
+    expect(PlatformWebViewController(params), isNotNull);
+  });
+
+  test('Can be mocked with `implements`', () {
+    when((WebViewPlatform.instance! as MockWebViewPlatform)
+            .createPlatformWebViewController(any))
+        .thenReturn(MockWebViewControllerDelegate());
+
+    expect(
+        PlatformWebViewController(
+            const PlatformWebViewControllerCreationParams()),
+        isNotNull);
+  });
+
+  test(
+      // ignore: lines_longer_than_80_chars
+      'Default implementation of loadFile should throw unimplemented error',
+      () {
+    final PlatformWebViewController controller =
+        ExtendsPlatformWebViewController(
+            const PlatformWebViewControllerCreationParams());
+
+    expect(
+      () => controller.loadFile(''),
+      throwsUnimplementedError,
+    );
+  });
+
+  test(
+      // ignore: lines_longer_than_80_chars
+      'Default implementation of loadFlutterAsset should throw unimplemented error',
+      () {
+    final PlatformWebViewController controller =
+        ExtendsPlatformWebViewController(
+            const PlatformWebViewControllerCreationParams());
+
+    expect(
+      () => controller.loadFlutterAsset(''),
+      throwsUnimplementedError,
+    );
+  });
+
+  test(
+      // ignore: lines_longer_than_80_chars
+      'Default implementation of loadHtmlString should throw unimplemented error',
+      () {
+    final PlatformWebViewController controller =
+        ExtendsPlatformWebViewController(
+            const PlatformWebViewControllerCreationParams());
+
+    expect(
+      () => controller.loadHtmlString(''),
+      throwsUnimplementedError,
+    );
+  });
+
+  test(
+      // ignore: lines_longer_than_80_chars
+      'Default implementation of loadRequest should throw unimplemented error',
+      () {
+    final PlatformWebViewController controller =
+        ExtendsPlatformWebViewController(
+            const PlatformWebViewControllerCreationParams());
+
+    expect(
+      () => controller.loadRequest(MockLoadRequestParamsDelegate()),
+      throwsUnimplementedError,
+    );
+  });
+
+  test(
+      // ignore: lines_longer_than_80_chars
+      'Default implementation of currentUrl should throw unimplemented error',
+      () {
+    final PlatformWebViewController controller =
+        ExtendsPlatformWebViewController(
+            const PlatformWebViewControllerCreationParams());
+
+    expect(
+      () => controller.currentUrl(),
+      throwsUnimplementedError,
+    );
+  });
+
+  test(
+      // ignore: lines_longer_than_80_chars
+      'Default implementation of canGoBack should throw unimplemented error',
+      () {
+    final PlatformWebViewController controller =
+        ExtendsPlatformWebViewController(
+            const PlatformWebViewControllerCreationParams());
+
+    expect(
+      () => controller.canGoBack(),
+      throwsUnimplementedError,
+    );
+  });
+
+  test(
+      // ignore: lines_longer_than_80_chars
+      'Default implementation of canGoForward should throw unimplemented error',
+      () {
+    final PlatformWebViewController controller =
+        ExtendsPlatformWebViewController(
+            const PlatformWebViewControllerCreationParams());
+
+    expect(
+      () => controller.canGoForward(),
+      throwsUnimplementedError,
+    );
+  });
+
+  test(
+      // ignore: lines_longer_than_80_chars
+      'Default implementation of goBack should throw unimplemented error', () {
+    final PlatformWebViewController controller =
+        ExtendsPlatformWebViewController(
+            const PlatformWebViewControllerCreationParams());
+
+    expect(
+      () => controller.goBack(),
+      throwsUnimplementedError,
+    );
+  });
+
+  test(
+      // ignore: lines_longer_than_80_chars
+      'Default implementation of goForward should throw unimplemented error',
+      () {
+    final PlatformWebViewController controller =
+        ExtendsPlatformWebViewController(
+            const PlatformWebViewControllerCreationParams());
+
+    expect(
+      () => controller.goForward(),
+      throwsUnimplementedError,
+    );
+  });
+
+  test(
+      // ignore: lines_longer_than_80_chars
+      'Default implementation of reload should throw unimplemented error', () {
+    final PlatformWebViewController controller =
+        ExtendsPlatformWebViewController(
+            const PlatformWebViewControllerCreationParams());
+
+    expect(
+      () => controller.reload(),
+      throwsUnimplementedError,
+    );
+  });
+
+  test(
+      // ignore: lines_longer_than_80_chars
+      'Default implementation of clearCache should throw unimplemented error',
+      () {
+    final PlatformWebViewController controller =
+        ExtendsPlatformWebViewController(
+            const PlatformWebViewControllerCreationParams());
+
+    expect(
+      () => controller.clearCache(),
+      throwsUnimplementedError,
+    );
+  });
+
+  test(
+      // ignore: lines_longer_than_80_chars
+      'Default implementation of clearLocalStorage should throw unimplemented error',
+      () {
+    final PlatformWebViewController controller =
+        ExtendsPlatformWebViewController(
+            const PlatformWebViewControllerCreationParams());
+
+    expect(
+      () => controller.clearLocalStorage(),
+      throwsUnimplementedError,
+    );
+  });
+
+  test(
+    'Default implementation of the setNavigationCallback should throw unimplemented error',
+    () {
+      final PlatformWebViewController controller =
+          ExtendsPlatformWebViewController(
+              const PlatformWebViewControllerCreationParams());
+
+      expect(
+        () =>
+            controller.setPlatformNavigationDelegate(MockNavigationDelegate()),
+        throwsUnimplementedError,
+      );
+    },
+  );
+
+  test(
+      // ignore: lines_longer_than_80_chars
+      'Default implementation of runJavaScript should throw unimplemented error',
+      () {
+    final PlatformWebViewController controller =
+        ExtendsPlatformWebViewController(
+            const PlatformWebViewControllerCreationParams());
+
+    expect(
+      () => controller.runJavaScript('javaScript'),
+      throwsUnimplementedError,
+    );
+  });
+
+  test(
+      // ignore: lines_longer_than_80_chars
+      'Default implementation of runJavaScriptReturningResult should throw unimplemented error',
+      () {
+    final PlatformWebViewController controller =
+        ExtendsPlatformWebViewController(
+            const PlatformWebViewControllerCreationParams());
+
+    expect(
+      () => controller.runJavaScriptReturningResult('javaScript'),
+      throwsUnimplementedError,
+    );
+  });
+
+  test(
+      // ignore: lines_longer_than_80_chars
+      'Default implementation of addJavaScriptChannel should throw unimplemented error',
+      () {
+    final PlatformWebViewController controller =
+        ExtendsPlatformWebViewController(
+            const PlatformWebViewControllerCreationParams());
+
+    expect(
+      () => controller.addJavaScriptChannel(
+        JavaScriptChannelParams(
+          name: 'test',
+          onMessageReceived: (_) {},
+        ),
+      ),
+      throwsUnimplementedError,
+    );
+  });
+
+  test(
+      // ignore: lines_longer_than_80_chars
+      'Default implementation of removeJavaScriptChannel should throw unimplemented error',
+      () {
+    final PlatformWebViewController controller =
+        ExtendsPlatformWebViewController(
+            const PlatformWebViewControllerCreationParams());
+
+    expect(
+      () => controller.removeJavaScriptChannel('test'),
+      throwsUnimplementedError,
+    );
+  });
+
+  test(
+      // ignore: lines_longer_than_80_chars
+      'Default implementation of getTitle should throw unimplemented error',
+      () {
+    final PlatformWebViewController controller =
+        ExtendsPlatformWebViewController(
+            const PlatformWebViewControllerCreationParams());
+
+    expect(
+      () => controller.getTitle(),
+      throwsUnimplementedError,
+    );
+  });
+
+  test(
+      // ignore: lines_longer_than_80_chars
+      'Default implementation of scrollTo should throw unimplemented error',
+      () {
+    final PlatformWebViewController controller =
+        ExtendsPlatformWebViewController(
+            const PlatformWebViewControllerCreationParams());
+
+    expect(
+      () => controller.scrollTo(0, 0),
+      throwsUnimplementedError,
+    );
+  });
+
+  test(
+      // ignore: lines_longer_than_80_chars
+      'Default implementation of scrollBy should throw unimplemented error',
+      () {
+    final PlatformWebViewController controller =
+        ExtendsPlatformWebViewController(
+            const PlatformWebViewControllerCreationParams());
+
+    expect(
+      () => controller.scrollBy(0, 0),
+      throwsUnimplementedError,
+    );
+  });
+
+  test(
+      // ignore: lines_longer_than_80_chars
+      'Default implementation of getScrollPosition should throw unimplemented error',
+      () {
+    final PlatformWebViewController controller =
+        ExtendsPlatformWebViewController(
+            const PlatformWebViewControllerCreationParams());
+
+    expect(
+      () => controller.getScrollPosition(),
+      throwsUnimplementedError,
+    );
+  });
+
+  test(
+      // ignore: lines_longer_than_80_chars
+      'Default implementation of enableDebugging should throw unimplemented error',
+      () {
+    final PlatformWebViewController controller =
+        ExtendsPlatformWebViewController(
+            const PlatformWebViewControllerCreationParams());
+
+    expect(
+      () => controller.enableDebugging(true),
+      throwsUnimplementedError,
+    );
+  });
+
+  test(
+      // ignore: lines_longer_than_80_chars
+      'Default implementation of enableGestureNavigation should throw unimplemented error',
+      () {
+    final PlatformWebViewController controller =
+        ExtendsPlatformWebViewController(
+            const PlatformWebViewControllerCreationParams());
+
+    expect(
+      () => controller.enableGestureNavigation(true),
+      throwsUnimplementedError,
+    );
+  });
+
+  test(
+      // ignore: lines_longer_than_80_chars
+      'Default implementation of enableZoom should throw unimplemented error',
+      () {
+    final PlatformWebViewController controller =
+        ExtendsPlatformWebViewController(
+            const PlatformWebViewControllerCreationParams());
+
+    expect(
+      () => controller.enableZoom(true),
+      throwsUnimplementedError,
+    );
+  });
+
+  test(
+      // ignore: lines_longer_than_80_chars
+      'Default implementation of setBackgroundColor should throw unimplemented error',
+      () {
+    final PlatformWebViewController controller =
+        ExtendsPlatformWebViewController(
+            const PlatformWebViewControllerCreationParams());
+
+    expect(
+      () => controller.setBackgroundColor(Colors.blue),
+      throwsUnimplementedError,
+    );
+  });
+
+  test(
+      // ignore: lines_longer_than_80_chars
+      'Default implementation of setJavaScriptMode should throw unimplemented error',
+      () {
+    final PlatformWebViewController controller =
+        ExtendsPlatformWebViewController(
+            const PlatformWebViewControllerCreationParams());
+
+    expect(
+      () => controller.setJavaScriptMode(JavaScriptMode.disabled),
+      throwsUnimplementedError,
+    );
+  });
+
+  test(
+      // ignore: lines_longer_than_80_chars
+      'Default implementation of setUserAgent should throw unimplemented error',
+      () {
+    final PlatformWebViewController controller =
+        ExtendsPlatformWebViewController(
+            const PlatformWebViewControllerCreationParams());
+
+    expect(
+      () => controller.setUserAgent(null),
+      throwsUnimplementedError,
+    );
+  });
+}
+
+class MockWebViewPlatformWithMixin extends MockWebViewPlatform
+    with
+        // ignore: prefer_mixin
+        MockPlatformInterfaceMixin {}
+
+class ImplementsPlatformWebViewController implements PlatformWebViewController {
+  @override
+  dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+}
+
+class MockWebViewControllerDelegate extends Mock
+    with
+        // ignore: prefer_mixin
+        MockPlatformInterfaceMixin
+    implements
+        PlatformWebViewController {}
+
+class ExtendsPlatformWebViewController extends PlatformWebViewController {
+  ExtendsPlatformWebViewController(
+      PlatformWebViewControllerCreationParams params)
+      : super.implementation(params);
+}
+
+// ignore: must_be_immutable
+class MockLoadRequestParamsDelegate extends Mock
+    with
+        //ignore: prefer_mixin
+        MockPlatformInterfaceMixin
+    implements
+        LoadRequestParams {}
diff --git a/packages/webview_flutter/webview_flutter_platform_interface/test/src/v4/platform_webview_controller_test.mocks.dart b/packages/webview_flutter/webview_flutter_platform_interface/test/src/v4/platform_webview_controller_test.mocks.dart
new file mode 100644
index 0000000..47e6737
--- /dev/null
+++ b/packages/webview_flutter/webview_flutter_platform_interface/test/src/v4/platform_webview_controller_test.mocks.dart
@@ -0,0 +1,72 @@
+// Mocks generated by Mockito 5.0.16 from annotations
+// in webview_flutter_platform_interface/test/src/v4/platform_webview_controller_test.dart.
+// Do not manually edit this file.
+
+import 'dart:async' as _i4;
+
+import 'package:mockito/mockito.dart' as _i1;
+import 'package:webview_flutter_platform_interface/v4/src/platform_navigation_delegate.dart'
+    as _i3;
+import 'package:webview_flutter_platform_interface/v4/src/webview_platform.dart'
+    as _i2;
+
+// 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 _FakePlatformNavigationDelegateCreationParams_0 extends _i1.Fake
+    implements _i2.PlatformNavigationDelegateCreationParams {}
+
+/// A class which mocks [PlatformNavigationDelegate].
+///
+/// See the documentation for Mockito's code generation for more information.
+class MockPlatformNavigationDelegate extends _i1.Mock
+    implements _i3.PlatformNavigationDelegate {
+  MockPlatformNavigationDelegate() {
+    _i1.throwOnMissingStub(this);
+  }
+
+  @override
+  _i2.PlatformNavigationDelegateCreationParams get params =>
+      (super.noSuchMethod(Invocation.getter(#params),
+              returnValue: _FakePlatformNavigationDelegateCreationParams_0())
+          as _i2.PlatformNavigationDelegateCreationParams);
+  @override
+  _i4.Future<void> setOnNavigationRequest(
+          _i4.FutureOr<bool> Function({bool isForMainFrame, String url})?
+              onNavigationRequest) =>
+      (super.noSuchMethod(
+          Invocation.method(#setOnNavigationRequest, [onNavigationRequest]),
+          returnValue: Future<void>.value(),
+          returnValueForMissingStub: Future<void>.value()) as _i4.Future<void>);
+  @override
+  _i4.Future<void> setOnPageStarted(void Function(String)? onPageStarted) =>
+      (super.noSuchMethod(Invocation.method(#setOnPageStarted, [onPageStarted]),
+          returnValue: Future<void>.value(),
+          returnValueForMissingStub: Future<void>.value()) as _i4.Future<void>);
+  @override
+  _i4.Future<void> setOnPageFinished(void Function(String)? onPageFinished) =>
+      (super.noSuchMethod(
+          Invocation.method(#setOnPageFinished, [onPageFinished]),
+          returnValue: Future<void>.value(),
+          returnValueForMissingStub: Future<void>.value()) as _i4.Future<void>);
+  @override
+  _i4.Future<void> setOnProgress(void Function(int)? onProgress) =>
+      (super.noSuchMethod(Invocation.method(#setOnProgress, [onProgress]),
+          returnValue: Future<void>.value(),
+          returnValueForMissingStub: Future<void>.value()) as _i4.Future<void>);
+  @override
+  _i4.Future<void> setOnWebResourceError(
+          void Function(_i2.WebResourceError)? onWebResourceError) =>
+      (super.noSuchMethod(
+          Invocation.method(#setOnWebResourceError, [onWebResourceError]),
+          returnValue: Future<void>.value(),
+          returnValueForMissingStub: Future<void>.value()) as _i4.Future<void>);
+  @override
+  String toString() => super.toString();
+}
diff --git a/packages/webview_flutter/webview_flutter_platform_interface/test/src/v4/platform_webview_widget_test.dart b/packages/webview_flutter/webview_flutter_platform_interface/test/src/v4/platform_webview_widget_test.dart
new file mode 100644
index 0000000..30fa52e
--- /dev/null
+++ b/packages/webview_flutter/webview_flutter_platform_interface/test/src/v4/platform_webview_widget_test.dart
@@ -0,0 +1,89 @@
+// 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.
+
+import 'package:flutter/widgets.dart';
+import 'package:flutter_test/flutter_test.dart';
+import 'package:mockito/mockito.dart';
+import 'package:plugin_platform_interface/plugin_platform_interface.dart';
+import 'package:webview_flutter_platform_interface/v4/src/platform_webview_controller.dart';
+import 'package:webview_flutter_platform_interface/v4/src/platform_webview_widget.dart';
+import 'package:webview_flutter_platform_interface/v4/src/webview_platform.dart';
+
+import 'webview_platform_test.mocks.dart';
+
+void main() {
+  setUp(() {
+    WebViewPlatform.instance = MockWebViewPlatformWithMixin();
+  });
+
+  test('Cannot be implemented with `implements`', () {
+    final MockWebViewControllerDelegate controller =
+        MockWebViewControllerDelegate();
+    final PlatformWebViewWidgetCreationParams params =
+        PlatformWebViewWidgetCreationParams(controller: controller);
+    when(WebViewPlatform.instance!.createPlatformWebViewWidget(params))
+        .thenReturn(ImplementsWebViewWidgetDelegate());
+
+    expect(() {
+      PlatformWebViewWidget(params);
+    }, throwsNoSuchMethodError);
+  });
+
+  test('Can be extended', () {
+    final MockWebViewControllerDelegate controller =
+        MockWebViewControllerDelegate();
+    final PlatformWebViewWidgetCreationParams params =
+        PlatformWebViewWidgetCreationParams(controller: controller);
+    when(WebViewPlatform.instance!.createPlatformWebViewWidget(params))
+        .thenReturn(ExtendsWebViewWidgetDelegate(params));
+
+    expect(PlatformWebViewWidget(params), isNotNull);
+  });
+
+  test('Can be mocked with `implements`', () {
+    final MockWebViewControllerDelegate controller =
+        MockWebViewControllerDelegate();
+    final PlatformWebViewWidgetCreationParams params =
+        PlatformWebViewWidgetCreationParams(controller: controller);
+    when(WebViewPlatform.instance!.createPlatformWebViewWidget(params))
+        .thenReturn(MockWebViewWidgetDelegate());
+
+    expect(PlatformWebViewWidget(params), isNotNull);
+  });
+}
+
+class MockWebViewPlatformWithMixin extends MockWebViewPlatform
+    with
+        // ignore: prefer_mixin
+        MockPlatformInterfaceMixin {}
+
+class ImplementsWebViewWidgetDelegate implements PlatformWebViewWidget {
+  @override
+  dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+}
+
+class MockWebViewWidgetDelegate extends Mock
+    with
+        // ignore: prefer_mixin
+        MockPlatformInterfaceMixin
+    implements
+        PlatformWebViewWidget {}
+
+class ExtendsWebViewWidgetDelegate extends PlatformWebViewWidget {
+  ExtendsWebViewWidgetDelegate(PlatformWebViewWidgetCreationParams params)
+      : super.implementation(params);
+
+  @override
+  Widget build(BuildContext context) {
+    throw UnimplementedError(
+        'build is not implemented for ExtendedWebViewWidgetDelegate.');
+  }
+}
+
+class MockWebViewControllerDelegate extends Mock
+    with
+        // ignore: prefer_mixin
+        MockPlatformInterfaceMixin
+    implements
+        PlatformWebViewController {}
diff --git a/packages/webview_flutter/webview_flutter_platform_interface/test/src/v4/webview_platform_test.dart b/packages/webview_flutter/webview_flutter_platform_interface/test/src/v4/webview_platform_test.dart
new file mode 100644
index 0000000..f091569
--- /dev/null
+++ b/packages/webview_flutter/webview_flutter_platform_interface/test/src/v4/webview_platform_test.dart
@@ -0,0 +1,109 @@
+// 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.
+
+import 'package:flutter_test/flutter_test.dart';
+import 'package:mockito/annotations.dart';
+import 'package:mockito/mockito.dart';
+import 'package:plugin_platform_interface/plugin_platform_interface.dart';
+import 'package:webview_flutter_platform_interface/v4/src/platform_webview_controller.dart';
+import 'package:webview_flutter_platform_interface/v4/src/webview_platform.dart';
+
+import 'webview_platform_test.mocks.dart';
+
+@GenerateMocks(<Type>[WebViewPlatform])
+void main() {
+  TestWidgetsFlutterBinding.ensureInitialized();
+
+  test('Default instance WebViewPlatform instance should be null', () {
+    expect(WebViewPlatform.instance, isNull);
+  });
+
+  test('Cannot be implemented with `implements`', () {
+    expect(() {
+      WebViewPlatform.instance = ImplementsWebViewPlatform();
+    }, throwsNoSuchMethodError);
+  });
+
+  test('Can be extended', () {
+    WebViewPlatform.instance = ExtendsWebViewPlatform();
+  });
+
+  test('Can be mocked with `implements`', () {
+    final MockWebViewPlatform mock = MockWebViewPlatformWithMixin();
+    WebViewPlatform.instance = mock;
+  });
+
+  test(
+      // ignore: lines_longer_than_80_chars
+      'Default implementation of createCookieManagerDelegate should throw unimplemented error',
+      () {
+    final WebViewPlatform webViewPlatform = ExtendsWebViewPlatform();
+
+    expect(
+      () => webViewPlatform.createPlatformCookieManager(
+          const PlatformWebViewCookieManagerCreationParams()),
+      throwsUnimplementedError,
+    );
+  });
+
+  test(
+      // ignore: lines_longer_than_80_chars
+      'Default implementation of createNavigationCallbackHandlerDelegate should throw unimplemented error',
+      () {
+    final WebViewPlatform webViewPlatform = ExtendsWebViewPlatform();
+
+    expect(
+      () => webViewPlatform.createPlatformNavigationDelegate(
+          const PlatformNavigationDelegateCreationParams()),
+      throwsUnimplementedError,
+    );
+  });
+
+  test(
+      // ignore: lines_longer_than_80_chars
+      'Default implementation of createWebViewControllerDelegate should throw unimplemented error',
+      () {
+    final WebViewPlatform webViewPlatform = ExtendsWebViewPlatform();
+
+    expect(
+      () => webViewPlatform.createPlatformWebViewController(
+          const PlatformWebViewControllerCreationParams()),
+      throwsUnimplementedError,
+    );
+  });
+
+  test(
+      // ignore: lines_longer_than_80_chars
+      'Default implementation of createWebViewWidgetDelegate should throw unimplemented error',
+      () {
+    final WebViewPlatform webViewPlatform = ExtendsWebViewPlatform();
+    final MockWebViewControllerDelegate controller =
+        MockWebViewControllerDelegate();
+
+    expect(
+      () => webViewPlatform.createPlatformWebViewWidget(
+          PlatformWebViewWidgetCreationParams(controller: controller)),
+      throwsUnimplementedError,
+    );
+  });
+}
+
+class ImplementsWebViewPlatform implements WebViewPlatform {
+  @override
+  dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+}
+
+class MockWebViewPlatformWithMixin extends MockWebViewPlatform
+    with
+        // ignore: prefer_mixin
+        MockPlatformInterfaceMixin {}
+
+class ExtendsWebViewPlatform extends WebViewPlatform {}
+
+class MockWebViewControllerDelegate extends Mock
+    with
+        // ignore: prefer_mixin
+        MockPlatformInterfaceMixin
+    implements
+        PlatformWebViewController {}
diff --git a/packages/webview_flutter/webview_flutter_platform_interface/test/src/v4/webview_platform_test.mocks.dart b/packages/webview_flutter/webview_flutter_platform_interface/test/src/v4/webview_platform_test.mocks.dart
new file mode 100644
index 0000000..5ce0075
--- /dev/null
+++ b/packages/webview_flutter/webview_flutter_platform_interface/test/src/v4/webview_platform_test.mocks.dart
@@ -0,0 +1,78 @@
+// Mocks generated by Mockito 5.0.16 from annotations
+// in webview_flutter_platform_interface/test/src/v4/webview_platform_test.dart.
+// Do not manually edit this file.
+
+import 'package:mockito/mockito.dart' as _i1;
+import 'package:webview_flutter_platform_interface/v4/src/platform_navigation_delegate.dart'
+    as _i3;
+import 'package:webview_flutter_platform_interface/v4/src/platform_webview_controller.dart'
+    as _i4;
+import 'package:webview_flutter_platform_interface/v4/src/platform_webview_cookie_manager.dart'
+    as _i2;
+import 'package:webview_flutter_platform_interface/v4/src/platform_webview_widget.dart'
+    as _i5;
+import 'package:webview_flutter_platform_interface/v4/src/types/types.dart'
+    as _i7;
+import 'package:webview_flutter_platform_interface/v4/src/webview_platform.dart'
+    as _i6;
+
+// 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 _FakePlatformWebViewCookieManager_0 extends _i1.Fake
+    implements _i2.PlatformWebViewCookieManager {}
+
+class _FakePlatformNavigationDelegate_1 extends _i1.Fake
+    implements _i3.PlatformNavigationDelegate {}
+
+class _FakePlatformWebViewController_2 extends _i1.Fake
+    implements _i4.PlatformWebViewController {}
+
+class _FakePlatformWebViewWidget_3 extends _i1.Fake
+    implements _i5.PlatformWebViewWidget {}
+
+/// A class which mocks [WebViewPlatform].
+///
+/// See the documentation for Mockito's code generation for more information.
+class MockWebViewPlatform extends _i1.Mock implements _i6.WebViewPlatform {
+  MockWebViewPlatform() {
+    _i1.throwOnMissingStub(this);
+  }
+
+  @override
+  _i2.PlatformWebViewCookieManager createPlatformCookieManager(
+          _i7.PlatformWebViewCookieManagerCreationParams? params) =>
+      (super.noSuchMethod(
+              Invocation.method(#createPlatformCookieManager, [params]),
+              returnValue: _FakePlatformWebViewCookieManager_0())
+          as _i2.PlatformWebViewCookieManager);
+  @override
+  _i3.PlatformNavigationDelegate createPlatformNavigationDelegate(
+          _i7.PlatformNavigationDelegateCreationParams? params) =>
+      (super.noSuchMethod(
+              Invocation.method(#createPlatformNavigationDelegate, [params]),
+              returnValue: _FakePlatformNavigationDelegate_1())
+          as _i3.PlatformNavigationDelegate);
+  @override
+  _i4.PlatformWebViewController createPlatformWebViewController(
+          _i7.PlatformWebViewControllerCreationParams? params) =>
+      (super.noSuchMethod(
+              Invocation.method(#createPlatformWebViewController, [params]),
+              returnValue: _FakePlatformWebViewController_2())
+          as _i4.PlatformWebViewController);
+  @override
+  _i5.PlatformWebViewWidget createPlatformWebViewWidget(
+          _i7.PlatformWebViewWidgetCreationParams? params) =>
+      (super.noSuchMethod(
+              Invocation.method(#createPlatformWebViewWidget, [params]),
+              returnValue: _FakePlatformWebViewWidget_3())
+          as _i5.PlatformWebViewWidget);
+  @override
+  String toString() => super.toString();
+}