[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();
+}