[webview_flutter_android] Add `Copyable` mixin and implement for all non-data and non-global classes (#6079)

diff --git a/packages/webview_flutter/webview_flutter_android/CHANGELOG.md b/packages/webview_flutter/webview_flutter_android/CHANGELOG.md
index a8e9a92..ceaef43 100644
--- a/packages/webview_flutter/webview_flutter_android/CHANGELOG.md
+++ b/packages/webview_flutter/webview_flutter_android/CHANGELOG.md
@@ -1,3 +1,8 @@
+## 2.9.1
+
+* Updates Android WebView classes as Copyable. This is a part of moving the api to handle garbage
+  collection automatically. See https://github.com/flutter/flutter/issues/107199.
+
 ## 2.9.0
 
 * Ignores unnecessary import warnings in preparation for [upcoming Flutter changes](https://github.com/flutter/flutter/pull/106316).
diff --git a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.dart b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.dart
index 7fdcf4b..005e281 100644
--- a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.dart
+++ b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.dart
@@ -2,6 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// TODO(bparrishMines): Replace unused callback methods in constructors with
+// variables once automatic garbage collection is fully implemented. See
+// https://github.com/flutter/flutter/issues/107199.
+// ignore_for_file: avoid_unused_constructor_parameters
+
 // TODO(a14n): remove this import once Flutter 3.1 or later reaches stable (including flutter/flutter#104231)
 // ignore: unnecessary_import
 import 'dart:typed_data';
@@ -12,6 +17,18 @@
 
 import 'android_webview.pigeon.dart';
 import 'android_webview_api_impls.dart';
+import 'instance_manager.dart';
+
+/// Root of the Java class hierarchy.
+///
+/// See https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html.
+abstract class JavaObject with Copyable {
+  /// Constructs a [JavaObject] without creating the associated Java object.
+  ///
+  /// This should only be used by subclasses created by this library or to
+  /// create copies.
+  JavaObject.detached();
+}
 
 /// An Android View that displays web pages.
 ///
@@ -32,12 +49,18 @@
 /// [Web-based content](https://developer.android.com/guide/webapps).
 ///
 /// When a [WebView] is no longer needed [release] must be called.
-class WebView {
+class WebView extends JavaObject {
   /// Constructs a new WebView.
-  WebView({this.useHybridComposition = false}) {
+  WebView({this.useHybridComposition = false}) : super.detached() {
     api.createFromInstance(this);
   }
 
+  /// Constructs a [WebView] without creating the associated Java object.
+  ///
+  /// This should only be used by subclasses created by this library or to
+  /// create copies.
+  WebView.detached({this.useHybridComposition = false}) : super.detached();
+
   /// Pigeon Host Api implementation for [WebView].
   @visibleForTesting
   static WebViewHostApiImpl api = WebViewHostApiImpl();
@@ -363,6 +386,11 @@
     WebSettings.api.disposeFromInstance(settings);
     return api.disposeFromInstance(this);
   }
+
+  @override
+  WebView copy() {
+    return WebView.detached(useHybridComposition: useHybridComposition);
+  }
 }
 
 /// Manages cookies globally for all webviews.
@@ -415,16 +443,22 @@
 /// obtained from [WebView.settings] is tied to the life of the WebView. If a
 /// WebView has been destroyed, any method call on [WebSettings] will throw an
 /// Exception.
-class WebSettings {
+class WebSettings extends JavaObject {
   /// Constructs a [WebSettings].
   ///
   /// This constructor is only used for testing. An instance should be obtained
   /// with [WebView.settings].
   @visibleForTesting
-  WebSettings(WebView webView) {
+  WebSettings(WebView webView) : super.detached() {
     api.createFromInstance(this, webView);
   }
 
+  /// Constructs a [WebSettings] without creating the associated Java object.
+  ///
+  /// This should only be used by subclasses created by this library or to
+  /// create copies.
+  WebSettings.detached() : super.detached();
+
   /// Pigeon Host Api implementation for [WebSettings].
   @visibleForTesting
   static WebSettingsHostApiImpl api = WebSettingsHostApiImpl();
@@ -546,17 +580,35 @@
   Future<void> setAllowFileAccess(bool enabled) {
     return api.setAllowFileAccessFromInstance(this, enabled);
   }
+
+  @override
+  WebSettings copy() {
+    return WebSettings.detached();
+  }
 }
 
 /// Exposes a channel to receive calls from javaScript.
 ///
 /// See [WebView.addJavaScriptChannel].
-abstract class JavaScriptChannel {
+class JavaScriptChannel extends JavaObject {
   /// Constructs a [JavaScriptChannel].
-  JavaScriptChannel(this.channelName) {
+  JavaScriptChannel(
+    this.channelName, {
+    void Function(String message)? postMessage,
+  }) : super.detached() {
     AndroidWebViewFlutterApis.instance.ensureSetUp();
   }
 
+  /// Constructs a [JavaScriptChannel] without creating the associated Java
+  /// object.
+  ///
+  /// This should only be used by subclasses created by this library or to
+  /// create copies.
+  JavaScriptChannel.detached(
+    this.channelName, {
+    void Function(String message)? postMessage,
+  }) : super.detached();
+
   /// Pigeon Host Api implementation for [JavaScriptChannel].
   @visibleForTesting
   static JavaScriptChannelHostApiImpl api = JavaScriptChannelHostApiImpl();
@@ -565,16 +617,65 @@
   final String channelName;
 
   /// Callback method when javaScript calls `postMessage` on the object instance passed.
-  void postMessage(String message);
+  void postMessage(String message) {}
+
+  @override
+  JavaScriptChannel copy() {
+    return JavaScriptChannel.detached(channelName, postMessage: postMessage);
+  }
 }
 
 /// Receive various notifications and requests for [WebView].
-abstract class WebViewClient {
+class WebViewClient extends JavaObject {
   /// Constructs a [WebViewClient].
-  WebViewClient({this.shouldOverrideUrlLoading = true}) {
+  WebViewClient({
+    this.shouldOverrideUrlLoading = true,
+    void Function(WebView webView, String url)? onPageStarted,
+    void Function(WebView webView, String url)? onPageFinished,
+    void Function(
+      WebView webView,
+      WebResourceRequest request,
+      WebResourceError error,
+    )?
+        onReceivedRequestError,
+    void Function(
+      WebView webView,
+      int errorCode,
+      String description,
+      String failingUrl,
+    )?
+        onReceivedError,
+    void Function(WebView webView, WebResourceRequest request)? requestLoading,
+    void Function(WebView webView, String url)? urlLoading,
+  }) : super.detached() {
     AndroidWebViewFlutterApis.instance.ensureSetUp();
   }
 
+  /// Constructs a [WebViewClient] without creating the associated Java object.
+  ///
+  /// This should only be used by subclasses created by this library or to
+  /// create copies.
+  WebViewClient.detached({
+    this.shouldOverrideUrlLoading = true,
+    void Function(WebView webView, String url)? onPageStarted,
+    void Function(WebView webView, String url)? onPageFinished,
+    void Function(
+      WebView webView,
+      WebResourceRequest request,
+      WebResourceError error,
+    )?
+        onReceivedRequestError,
+    void Function(
+      WebView webView,
+      int errorCode,
+      String description,
+      String failingUrl,
+    )?
+        onReceivedError,
+    void Function(WebView webView, WebResourceRequest request)? requestLoading,
+    void Function(WebView webView, String url)? urlLoading,
+  }) : super.detached();
+
   /// User authentication failed on server.
   ///
   /// See https://developer.android.com/reference/android/webkit/WebViewClient#ERROR_AUTHENTICATION
@@ -735,15 +836,54 @@
   /// causes the current [WebView] to abort loading the URL, while returning
   /// false causes the [WebView] to continue loading the URL as usual.
   void urlLoading(WebView webView, String url) {}
+
+  @override
+  WebViewClient copy() {
+    return WebViewClient.detached(
+      shouldOverrideUrlLoading: shouldOverrideUrlLoading,
+      onPageStarted: onPageStarted,
+      onPageFinished: onPageFinished,
+      onReceivedRequestError: onReceivedRequestError,
+      onReceivedError: onReceivedError,
+      requestLoading: requestLoading,
+      urlLoading: urlLoading,
+    );
+  }
 }
 
-/// The interface to be used when content can not be handled by the rendering engine for [WebView], and should be downloaded instead.
-abstract class DownloadListener {
+/// The interface to be used when content can not be handled by the rendering
+/// engine for [WebView], and should be downloaded instead.
+class DownloadListener extends JavaObject {
   /// Constructs a [DownloadListener].
-  DownloadListener() {
+  DownloadListener({
+    void Function(
+      String url,
+      String userAgent,
+      String contentDisposition,
+      String mimetype,
+      int contentLength,
+    )?
+        onDownloadStart,
+  }) : super.detached() {
     AndroidWebViewFlutterApis.instance.ensureSetUp();
   }
 
+  /// Constructs a [DownloadListener] without creating the associated Java
+  /// object.
+  ///
+  /// This should only be used by subclasses created by this library or to
+  /// create copies.
+  DownloadListener.detached({
+    void Function(
+      String url,
+      String userAgent,
+      String contentDisposition,
+      String mimetype,
+      int contentLength,
+    )?
+        onDownloadStart,
+  }) : super.detached();
+
   /// Pigeon Host Api implementation for [DownloadListener].
   @visibleForTesting
   static DownloadListenerHostApiImpl api = DownloadListenerHostApiImpl();
@@ -755,22 +895,43 @@
     String contentDisposition,
     String mimetype,
     int contentLength,
-  );
+  ) {}
+
+  @override
+  DownloadListener copy() {
+    return DownloadListener(onDownloadStart: onDownloadStart);
+  }
 }
 
 /// Handles JavaScript dialogs, favicons, titles, and the progress for [WebView].
-abstract class WebChromeClient {
+class WebChromeClient extends JavaObject {
   /// Constructs a [WebChromeClient].
-  WebChromeClient() {
+  WebChromeClient({
+    void Function(WebView webView, int progress)? onProgressChanged,
+  }) : super.detached() {
     AndroidWebViewFlutterApis.instance.ensureSetUp();
   }
 
+  /// Constructs a [WebChromeClient] without creating the associated Java
+  /// object.
+  ///
+  /// This should only be used by subclasses created by this library or to
+  /// create copies.
+  WebChromeClient.detached({
+    void Function(WebView webView, int progress)? onProgressChanged,
+  }) : super.detached();
+
   /// Pigeon Host Api implementation for [WebChromeClient].
   @visibleForTesting
   static WebChromeClientHostApiImpl api = WebChromeClientHostApiImpl();
 
   /// Notify the host application that a file should be downloaded.
   void onProgressChanged(WebView webView, int progress) {}
+
+  @override
+  WebChromeClient copy() {
+    return WebChromeClient.detached(onProgressChanged: onProgressChanged);
+  }
 }
 
 /// Encompasses parameters to the [WebViewClient.requestLoading] method.
@@ -846,17 +1007,23 @@
 /// Manages the JavaScript storage APIs provided by the [WebView].
 ///
 /// Wraps [WebStorage](https://developer.android.com/reference/android/webkit/WebStorage).
-class WebStorage {
+class WebStorage extends JavaObject {
   /// Constructs a [WebStorage].
   ///
   /// This constructor is only used for testing. An instance should be obtained
   /// with [WebStorage.instance].
   @visibleForTesting
-  WebStorage() {
+  WebStorage() : super.detached() {
     AndroidWebViewFlutterApis.instance.ensureSetUp();
     api.createFromInstance(this);
   }
 
+  /// Constructs a [WebStorage] without creating the associated Java object.
+  ///
+  /// This should only be used by subclasses created by this library or to
+  /// create copies.
+  WebStorage.detached() : super.detached();
+
   /// Pigeon Host Api implementation for [WebStorage].
   @visibleForTesting
   static WebStorageHostApiImpl api = WebStorageHostApiImpl();
@@ -868,4 +1035,9 @@
   Future<void> deleteAllData() {
     return api.deleteAllDataFromInstance(this);
   }
+
+  @override
+  WebStorage copy() {
+    return WebStorage.detached();
+  }
 }
diff --git a/packages/webview_flutter/webview_flutter_android/lib/src/instance_manager.dart b/packages/webview_flutter/webview_flutter_android/lib/src/instance_manager.dart
index e6dd2b2..531fffa 100644
--- a/packages/webview_flutter/webview_flutter_android/lib/src/instance_manager.dart
+++ b/packages/webview_flutter/webview_flutter_android/lib/src/instance_manager.dart
@@ -2,6 +2,27 @@
 // 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';
+
+/// An immutable object that can provide functional copies of itself.
+///
+/// All implementers are expected to be immutable as defined by the annotation.
+// TODO(bparrishMines): Uncomment annotation once
+// https://github.com/flutter/plugins/pull/5831 lands or when making a breaking
+// change for https://github.com/flutter/flutter/issues/107199.
+// @immutable
+mixin Copyable {
+  /// Instantiates and returns a functionally identical object to oneself.
+  ///
+  /// Outside of tests, this method should only ever be called by
+  /// [InstanceManager].
+  ///
+  /// Subclasses should always override their parent's implementation of this
+  /// method.
+  @protected
+  Copyable copy();
+}
+
 /// Maintains instances stored to communicate with java objects.
 class InstanceManager {
   final Map<int, Object> _instanceIdsToInstances = <int, Object>{};
diff --git a/packages/webview_flutter/webview_flutter_android/pubspec.yaml b/packages/webview_flutter/webview_flutter_android/pubspec.yaml
index aaa4984..e530b1e 100644
--- a/packages/webview_flutter/webview_flutter_android/pubspec.yaml
+++ b/packages/webview_flutter/webview_flutter_android/pubspec.yaml
@@ -2,7 +2,7 @@
 description: A Flutter plugin that provides a WebView widget on Android.
 repository: https://github.com/flutter/plugins/tree/main/packages/webview_flutter/webview_flutter_android
 issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+webview%22
-version: 2.9.0
+version: 2.9.1
 
 environment:
   sdk: ">=2.14.0 <3.0.0"
diff --git a/packages/webview_flutter/webview_flutter_android/test/android_webview_test.dart b/packages/webview_flutter/webview_flutter_android/test/android_webview_test.dart
index 4c63ab0..cb2ea0f 100644
--- a/packages/webview_flutter/webview_flutter_android/test/android_webview_test.dart
+++ b/packages/webview_flutter/webview_flutter_android/test/android_webview_test.dart
@@ -318,6 +318,10 @@
         verify(mockWebSettingsPlatformHostApi.dispose(webSettingsInstanceId));
         verify(mockPlatformHostApi.dispose(webViewInstanceId));
       });
+
+      test('copy', () {
+        expect(webView.copy(), isA<WebView>());
+      });
     });
 
     group('WebSettings', () {
@@ -444,6 +448,10 @@
           true,
         ));
       });
+
+      test('copy', () {
+        expect(webSettings.copy(), isA<WebSettings>());
+      });
     });
 
     group('JavaScriptChannel', () {
@@ -472,6 +480,13 @@
         );
         verify(mockJavaScriptChannel.postMessage('Hello, World!'));
       });
+
+      test('copy', () {
+        expect(
+          JavaScriptChannel.detached('channel').copy(),
+          isA<JavaScriptChannel>(),
+        );
+      });
     });
 
     group('WebViewClient', () {
@@ -591,6 +606,10 @@
           'https://www.google.com',
         ));
       });
+
+      test('copy', () {
+        expect(WebViewClient.detached().copy(), isA<WebViewClient>());
+      });
     });
 
     group('DownloadListener', () {
@@ -629,6 +648,10 @@
           45,
         ));
       });
+
+      test('copy', () {
+        expect(DownloadListener.detached().copy(), isA<DownloadListener>());
+      });
     });
 
     group('WebChromeClient', () {
@@ -664,6 +687,10 @@
         );
         verify(mockWebChromeClient.onProgressChanged(mockWebView, 76));
       });
+
+      test('copy', () {
+        expect(WebChromeClient.detached().copy(), isA<WebChromeClient>());
+      });
     });
   });
 
@@ -706,5 +733,9 @@
       webStorage.deleteAllData();
       verify(mockPlatformHostApi.deleteAllData(webStorageInstanceId));
     });
+
+    test('copy', () {
+      expect(WebStorage.detached().copy(), isA<WebStorage>());
+    });
   });
 }
diff --git a/packages/webview_flutter/webview_flutter_android/test/android_webview_test.mocks.dart b/packages/webview_flutter/webview_flutter_android/test/android_webview_test.mocks.dart
index 85ab668..72d1d41 100644
--- a/packages/webview_flutter/webview_flutter_android/test/android_webview_test.mocks.dart
+++ b/packages/webview_flutter/webview_flutter_android/test/android_webview_test.mocks.dart
@@ -1,4 +1,4 @@
-// Mocks generated by Mockito 5.1.0 from annotations
+// Mocks generated by Mockito 5.2.0 from annotations
 // in webview_flutter_android/test/android_webview_test.dart.
 // Do not manually edit this file.
 
@@ -22,7 +22,19 @@
 // ignore_for_file: unnecessary_parenthesis
 // ignore_for_file: camel_case_types
 
-class _FakeWebSettings_0 extends _i1.Fake implements _i2.WebSettings {}
+class _FakeDownloadListener_0 extends _i1.Fake implements _i2.DownloadListener {
+}
+
+class _FakeJavaScriptChannel_1 extends _i1.Fake
+    implements _i2.JavaScriptChannel {}
+
+class _FakeWebChromeClient_2 extends _i1.Fake implements _i2.WebChromeClient {}
+
+class _FakeWebSettings_3 extends _i1.Fake implements _i2.WebSettings {}
+
+class _FakeWebView_4 extends _i1.Fake implements _i2.WebView {}
+
+class _FakeWebViewClient_5 extends _i1.Fake implements _i2.WebViewClient {}
 
 /// A class which mocks [CookieManagerHostApi].
 ///
@@ -47,6 +59,7 @@
 /// A class which mocks [DownloadListener].
 ///
 /// See the documentation for Mockito's code generation for more information.
+// ignore: must_be_immutable
 class MockDownloadListener extends _i1.Mock implements _i2.DownloadListener {
   MockDownloadListener() {
     _i1.throwOnMissingStub(this);
@@ -59,11 +72,16 @@
           Invocation.method(#onDownloadStart,
               [url, userAgent, contentDisposition, mimetype, contentLength]),
           returnValueForMissingStub: null);
+  @override
+  _i2.DownloadListener copy() =>
+      (super.noSuchMethod(Invocation.method(#copy, []),
+          returnValue: _FakeDownloadListener_0()) as _i2.DownloadListener);
 }
 
 /// A class which mocks [JavaScriptChannel].
 ///
 /// See the documentation for Mockito's code generation for more information.
+// ignore: must_be_immutable
 class MockJavaScriptChannel extends _i1.Mock implements _i2.JavaScriptChannel {
   MockJavaScriptChannel() {
     _i1.throwOnMissingStub(this);
@@ -77,6 +95,10 @@
   void postMessage(String? message) =>
       super.noSuchMethod(Invocation.method(#postMessage, [message]),
           returnValueForMissingStub: null);
+  @override
+  _i2.JavaScriptChannel copy() =>
+      (super.noSuchMethod(Invocation.method(#copy, []),
+          returnValue: _FakeJavaScriptChannel_1()) as _i2.JavaScriptChannel);
 }
 
 /// A class which mocks [TestDownloadListenerHostApi].
@@ -395,6 +417,7 @@
 /// A class which mocks [WebChromeClient].
 ///
 /// See the documentation for Mockito's code generation for more information.
+// ignore: must_be_immutable
 class MockWebChromeClient extends _i1.Mock implements _i2.WebChromeClient {
   MockWebChromeClient() {
     _i1.throwOnMissingStub(this);
@@ -404,11 +427,16 @@
   void onProgressChanged(_i2.WebView? webView, int? progress) => super
       .noSuchMethod(Invocation.method(#onProgressChanged, [webView, progress]),
           returnValueForMissingStub: null);
+  @override
+  _i2.WebChromeClient copy() =>
+      (super.noSuchMethod(Invocation.method(#copy, []),
+          returnValue: _FakeWebChromeClient_2()) as _i2.WebChromeClient);
 }
 
 /// A class which mocks [WebView].
 ///
 /// See the documentation for Mockito's code generation for more information.
+// ignore: must_be_immutable
 class MockWebView extends _i1.Mock implements _i2.WebView {
   MockWebView() {
     _i1.throwOnMissingStub(this);
@@ -421,7 +449,7 @@
   @override
   _i2.WebSettings get settings =>
       (super.noSuchMethod(Invocation.getter(#settings),
-          returnValue: _FakeWebSettings_0()) as _i2.WebSettings);
+          returnValue: _FakeWebSettings_3()) as _i2.WebSettings);
   @override
   _i4.Future<void> loadData(
           {String? data, String? mimeType, String? encoding}) =>
@@ -554,11 +582,15 @@
       (super.noSuchMethod(Invocation.method(#release, []),
           returnValue: Future<void>.value(),
           returnValueForMissingStub: Future<void>.value()) as _i4.Future<void>);
+  @override
+  _i2.WebView copy() => (super.noSuchMethod(Invocation.method(#copy, []),
+      returnValue: _FakeWebView_4()) as _i2.WebView);
 }
 
 /// A class which mocks [WebViewClient].
 ///
 /// See the documentation for Mockito's code generation for more information.
+// ignore: must_be_immutable
 class MockWebViewClient extends _i1.Mock implements _i2.WebViewClient {
   MockWebViewClient() {
     _i1.throwOnMissingStub(this);
@@ -597,4 +629,7 @@
   void urlLoading(_i2.WebView? webView, String? url) =>
       super.noSuchMethod(Invocation.method(#urlLoading, [webView, url]),
           returnValueForMissingStub: null);
+  @override
+  _i2.WebViewClient copy() => (super.noSuchMethod(Invocation.method(#copy, []),
+      returnValue: _FakeWebViewClient_5()) as _i2.WebViewClient);
 }
diff --git a/packages/webview_flutter/webview_flutter_android/test/webview_android_cookie_manager_test.mocks.dart b/packages/webview_flutter/webview_flutter_android/test/webview_android_cookie_manager_test.mocks.dart
index ff9974b..308aba4 100644
--- a/packages/webview_flutter/webview_flutter_android/test/webview_android_cookie_manager_test.mocks.dart
+++ b/packages/webview_flutter/webview_flutter_android/test/webview_android_cookie_manager_test.mocks.dart
@@ -1,4 +1,4 @@
-// Mocks generated by Mockito 5.1.0 from annotations
+// Mocks generated by Mockito 5.2.0 from annotations
 // in webview_flutter_android/test/webview_android_cookie_manager_test.dart.
 // Do not manually edit this file.
 
diff --git a/packages/webview_flutter/webview_flutter_android/test/webview_android_widget_test.mocks.dart b/packages/webview_flutter/webview_flutter_android/test/webview_android_widget_test.mocks.dart
index 78e60ca..f9e8838 100644
--- a/packages/webview_flutter/webview_flutter_android/test/webview_android_widget_test.mocks.dart
+++ b/packages/webview_flutter/webview_flutter_android/test/webview_android_widget_test.mocks.dart
@@ -1,4 +1,4 @@
-// Mocks generated by Mockito 5.1.0 from annotations
+// Mocks generated by Mockito 5.2.0 from annotations
 // in webview_flutter_android/test/webview_android_widget_test.dart.
 // Do not manually edit this file.
 
@@ -24,11 +24,23 @@
 
 class _FakeWebSettings_0 extends _i1.Fake implements _i2.WebSettings {}
 
-class _FakeJavascriptChannelRegistry_1 extends _i1.Fake
-    implements _i3.JavascriptChannelRegistry {}
+class _FakeWebStorage_1 extends _i1.Fake implements _i2.WebStorage {}
 
 class _FakeWebView_2 extends _i1.Fake implements _i2.WebView {}
 
+class _FakeDownloadListener_3 extends _i1.Fake implements _i2.DownloadListener {
+}
+
+class _FakeJavascriptChannelRegistry_4 extends _i1.Fake
+    implements _i3.JavascriptChannelRegistry {}
+
+class _FakeJavaScriptChannel_5 extends _i1.Fake
+    implements _i2.JavaScriptChannel {}
+
+class _FakeWebChromeClient_6 extends _i1.Fake implements _i2.WebChromeClient {}
+
+class _FakeWebViewClient_7 extends _i1.Fake implements _i2.WebViewClient {}
+
 /// A class which mocks [FlutterAssetManager].
 ///
 /// See the documentation for Mockito's code generation for more information.
@@ -52,6 +64,7 @@
 /// A class which mocks [WebSettings].
 ///
 /// See the documentation for Mockito's code generation for more information.
+// ignore: must_be_immutable
 class MockWebSettings extends _i1.Mock implements _i2.WebSettings {
   MockWebSettings() {
     _i1.throwOnMissingStub(this);
@@ -119,11 +132,15 @@
       (super.noSuchMethod(Invocation.method(#setAllowFileAccess, [enabled]),
           returnValue: Future<void>.value(),
           returnValueForMissingStub: Future<void>.value()) as _i4.Future<void>);
+  @override
+  _i2.WebSettings copy() => (super.noSuchMethod(Invocation.method(#copy, []),
+      returnValue: _FakeWebSettings_0()) as _i2.WebSettings);
 }
 
 /// A class which mocks [WebStorage].
 ///
 /// See the documentation for Mockito's code generation for more information.
+// ignore: must_be_immutable
 class MockWebStorage extends _i1.Mock implements _i2.WebStorage {
   MockWebStorage() {
     _i1.throwOnMissingStub(this);
@@ -134,11 +151,15 @@
       (super.noSuchMethod(Invocation.method(#deleteAllData, []),
           returnValue: Future<void>.value(),
           returnValueForMissingStub: Future<void>.value()) as _i4.Future<void>);
+  @override
+  _i2.WebStorage copy() => (super.noSuchMethod(Invocation.method(#copy, []),
+      returnValue: _FakeWebStorage_1()) as _i2.WebStorage);
 }
 
 /// A class which mocks [WebView].
 ///
 /// See the documentation for Mockito's code generation for more information.
+// ignore: must_be_immutable
 class MockWebView extends _i1.Mock implements _i2.WebView {
   MockWebView() {
     _i1.throwOnMissingStub(this);
@@ -284,6 +305,9 @@
       (super.noSuchMethod(Invocation.method(#release, []),
           returnValue: Future<void>.value(),
           returnValueForMissingStub: Future<void>.value()) as _i4.Future<void>);
+  @override
+  _i2.WebView copy() => (super.noSuchMethod(Invocation.method(#copy, []),
+      returnValue: _FakeWebView_2()) as _i2.WebView);
 }
 
 /// A class which mocks [WebResourceRequest].
@@ -338,6 +362,10 @@
           Invocation.method(#onDownloadStart,
               [url, userAgent, contentDisposition, mimetype, contentLength]),
           returnValueForMissingStub: null);
+  @override
+  _i2.DownloadListener copy() =>
+      (super.noSuchMethod(Invocation.method(#copy, []),
+          returnValue: _FakeDownloadListener_3()) as _i2.DownloadListener);
 }
 
 /// A class which mocks [WebViewAndroidJavaScriptChannel].
@@ -352,7 +380,7 @@
   @override
   _i3.JavascriptChannelRegistry get javascriptChannelRegistry =>
       (super.noSuchMethod(Invocation.getter(#javascriptChannelRegistry),
-              returnValue: _FakeJavascriptChannelRegistry_1())
+              returnValue: _FakeJavascriptChannelRegistry_4())
           as _i3.JavascriptChannelRegistry);
   @override
   String get channelName =>
@@ -362,6 +390,10 @@
   void postMessage(String? message) =>
       super.noSuchMethod(Invocation.method(#postMessage, [message]),
           returnValueForMissingStub: null);
+  @override
+  _i2.JavaScriptChannel copy() =>
+      (super.noSuchMethod(Invocation.method(#copy, []),
+          returnValue: _FakeJavaScriptChannel_5()) as _i2.JavaScriptChannel);
 }
 
 /// A class which mocks [WebViewAndroidWebChromeClient].
@@ -377,6 +409,10 @@
   void onProgressChanged(_i2.WebView? webView, int? progress) => super
       .noSuchMethod(Invocation.method(#onProgressChanged, [webView, progress]),
           returnValueForMissingStub: null);
+  @override
+  _i2.WebChromeClient copy() =>
+      (super.noSuchMethod(Invocation.method(#copy, []),
+          returnValue: _FakeWebChromeClient_6()) as _i2.WebChromeClient);
 }
 
 /// A class which mocks [WebViewAndroidWebViewClient].
@@ -445,6 +481,9 @@
   void requestLoading(_i2.WebView? webView, _i2.WebResourceRequest? request) =>
       super.noSuchMethod(Invocation.method(#requestLoading, [webView, request]),
           returnValueForMissingStub: null);
+  @override
+  _i2.WebViewClient copy() => (super.noSuchMethod(Invocation.method(#copy, []),
+      returnValue: _FakeWebViewClient_7()) as _i2.WebViewClient);
 }
 
 /// A class which mocks [JavascriptChannelRegistry].