[webview_flutter_wkwebview][webview_flutter_android] Fixes bug where the `WebView`s could not be released (#6996)

* fix and test non disposing webview

* combine boolean

* version bump

* more pumpAndSettles

* add more pumpAndSettles

* update int tests

* android test

* fix version bump and unchange compile files

* make _currentNavigationDelegate nullable

* quick fix

* accidental letter

* small tests fixes

* missing hashtag
diff --git a/packages/webview_flutter/webview_flutter_android/CHANGELOG.md b/packages/webview_flutter/webview_flutter_android/CHANGELOG.md
index e1786d6..1a490b5 100644
--- a/packages/webview_flutter/webview_flutter_android/CHANGELOG.md
+++ b/packages/webview_flutter/webview_flutter_android/CHANGELOG.md
@@ -1,3 +1,8 @@
+## 3.2.3
+
+* Fixes bug that prevented the web view from being garbage collected.
+* Fixes bug causing a `LateInitializationError` when a `PlatformNavigationDelegate` is not provided.
+
 ## 3.2.2
 
 * Updates example code for `use_build_context_synchronously` lint.
diff --git a/packages/webview_flutter/webview_flutter_android/example/integration_test/webview_flutter_test.dart b/packages/webview_flutter/webview_flutter_android/example/integration_test/webview_flutter_test.dart
index 3f62053..af144e5 100644
--- a/packages/webview_flutter/webview_flutter_android/example/integration_test/webview_flutter_test.dart
+++ b/packages/webview_flutter/webview_flutter_android/example/integration_test/webview_flutter_test.dart
@@ -17,6 +17,8 @@
 import 'package:flutter/services.dart';
 import 'package:flutter_test/flutter_test.dart';
 import 'package:integration_test/integration_test.dart';
+import 'package:webview_flutter_android/src/android_webview.dart' as android;
+import 'package:webview_flutter_android/src/android_webview_api_impls.dart';
 import 'package:webview_flutter_android/src/instance_manager.dart';
 import 'package:webview_flutter_android/src/weak_reference_utils.dart';
 import 'package:webview_flutter_android/webview_flutter_android.dart';
@@ -58,15 +60,13 @@
       )
       ..loadRequest(LoadRequestParams(uri: Uri.parse(primaryUrl)));
 
-    await tester.pumpWidget(
-      Builder(
-        builder: (BuildContext context) {
-          return PlatformWebViewWidget(
-            PlatformWebViewWidgetCreationParams(controller: controller),
-          ).build(context);
-        },
-      ),
-    );
+    await tester.pumpWidget(Builder(
+      builder: (BuildContext context) {
+        return PlatformWebViewWidget(
+          PlatformWebViewWidgetCreationParams(controller: controller),
+        ).build(context);
+      },
+    ));
 
     await pageFinished.future;
 
@@ -96,6 +96,79 @@
     expect(gcIdentifier, 0);
   }, timeout: const Timeout(Duration(seconds: 10)));
 
+  testWidgets(
+    'WebView is released by garbage collection',
+    (WidgetTester tester) async {
+      final Completer<void> webViewGCCompleter = Completer<void>();
+
+      late final InstanceManager instanceManager;
+      instanceManager =
+          InstanceManager(onWeakReferenceRemoved: (int identifier) {
+        final Copyable instance =
+            instanceManager.getInstanceWithWeakReference(identifier)!;
+        if (instance is android.WebView && !webViewGCCompleter.isCompleted) {
+          webViewGCCompleter.complete();
+        }
+      });
+
+      android.WebView.api = WebViewHostApiImpl(
+        instanceManager: instanceManager,
+      );
+      android.WebSettings.api = WebSettingsHostApiImpl(
+        instanceManager: instanceManager,
+      );
+      android.WebChromeClient.api = WebChromeClientHostApiImpl(
+        instanceManager: instanceManager,
+      );
+
+      await tester.pumpWidget(
+        Builder(
+          builder: (BuildContext context) {
+            return PlatformWebViewWidget(
+              AndroidWebViewWidgetCreationParams(
+                instanceManager: instanceManager,
+                controller: PlatformWebViewController(
+                  const PlatformWebViewControllerCreationParams(),
+                ),
+              ),
+            ).build(context);
+          },
+        ),
+      );
+      await tester.pumpAndSettle();
+
+      await tester.pumpWidget(
+        Builder(
+          builder: (BuildContext context) {
+            return PlatformWebViewWidget(
+              AndroidWebViewWidgetCreationParams(
+                instanceManager: instanceManager,
+                controller: PlatformWebViewController(
+                  const PlatformWebViewControllerCreationParams(),
+                ),
+              ),
+            ).build(context);
+          },
+        ),
+      );
+      await tester.pumpAndSettle();
+
+      // Force garbage collection.
+      await IntegrationTestWidgetsFlutterBinding.instance
+          .watchPerformance(() async {
+        await tester.pumpAndSettle();
+      });
+
+      await tester.pumpAndSettle();
+      await expectLater(webViewGCCompleter.future, completes);
+
+      android.WebView.api = WebViewHostApiImpl();
+      android.WebSettings.api = WebSettingsHostApiImpl();
+      android.WebChromeClient.api = WebChromeClientHostApiImpl();
+    },
+    timeout: const Timeout(Duration(seconds: 10)),
+  );
+
   testWidgets('runJavaScriptReturningResult', (WidgetTester tester) async {
     final Completer<void> pageFinished = Completer<void>();
 
@@ -110,15 +183,13 @@
       )
       ..loadRequest(LoadRequestParams(uri: Uri.parse(primaryUrl)));
 
-    await tester.pumpWidget(
-      Builder(
-        builder: (BuildContext context) {
-          return PlatformWebViewWidget(
-            PlatformWebViewWidgetCreationParams(controller: controller),
-          ).build(context);
-        },
-      ),
-    );
+    await tester.pumpWidget(Builder(
+      builder: (BuildContext context) {
+        return PlatformWebViewWidget(
+          PlatformWebViewWidgetCreationParams(controller: controller),
+        ).build(context);
+      },
+    ));
 
     await pageFinished.future;
 
@@ -151,15 +222,13 @@
         ),
       );
 
-    await tester.pumpWidget(
-      Builder(
-        builder: (BuildContext context) {
-          return PlatformWebViewWidget(
-            PlatformWebViewWidgetCreationParams(controller: controller),
-          ).build(context);
-        },
-      ),
-    );
+    await tester.pumpWidget(Builder(
+      builder: (BuildContext context) {
+        return PlatformWebViewWidget(
+          PlatformWebViewWidgetCreationParams(controller: controller),
+        ).build(context);
+      },
+    ));
 
     await pageLoads.stream.firstWhere((String url) => url == headersUrl);
 
@@ -195,15 +264,13 @@
       'data:text/html;charset=utf-8;base64,PCFET0NUWVBFIGh0bWw+',
     );
 
-    await tester.pumpWidget(
-      Builder(
-        builder: (BuildContext context) {
-          return PlatformWebViewWidget(
-            PlatformWebViewWidgetCreationParams(controller: controller),
-          ).build(context);
-        },
-      ),
-    );
+    await tester.pumpWidget(Builder(
+      builder: (BuildContext context) {
+        return PlatformWebViewWidget(
+          PlatformWebViewWidgetCreationParams(controller: controller),
+        ).build(context);
+      },
+    ));
 
     await pageFinished.future;
 
@@ -258,15 +325,13 @@
       ..setUserAgent('Custom_User_Agent1')
       ..loadRequest(LoadRequestParams(uri: Uri.parse('about:blank')));
 
-    await tester.pumpWidget(
-      Builder(
-        builder: (BuildContext context) {
-          return PlatformWebViewWidget(
-            PlatformWebViewWidgetCreationParams(controller: controller),
-          ).build(context);
-        },
-      ),
-    );
+    await tester.pumpWidget(Builder(
+      builder: (BuildContext context) {
+        return PlatformWebViewWidget(
+          PlatformWebViewWidgetCreationParams(controller: controller),
+        ).build(context);
+      },
+    ));
 
     await pageFinished.future;
 
@@ -335,15 +400,13 @@
           ),
         );
 
-      await tester.pumpWidget(
-        Builder(
-          builder: (BuildContext context) {
-            return PlatformWebViewWidget(
-              PlatformWebViewWidgetCreationParams(controller: controller),
-            ).build(context);
-          },
-        ),
-      );
+      await tester.pumpWidget(Builder(
+        builder: (BuildContext context) {
+          return PlatformWebViewWidget(
+            PlatformWebViewWidgetCreationParams(controller: controller),
+          ).build(context);
+        },
+      ));
 
       await pageLoaded.future;
 
@@ -369,15 +432,13 @@
           ),
         );
 
-      await tester.pumpWidget(
-        Builder(
-          builder: (BuildContext context) {
-            return PlatformWebViewWidget(
-              PlatformWebViewWidgetCreationParams(controller: controller),
-            ).build(context);
-          },
-        ),
-      );
+      await tester.pumpWidget(Builder(
+        builder: (BuildContext context) {
+          return PlatformWebViewWidget(
+            PlatformWebViewWidgetCreationParams(controller: controller),
+          ).build(context);
+        },
+      ));
 
       await pageLoaded.future;
 
@@ -491,15 +552,13 @@
           ),
         );
 
-      await tester.pumpWidget(
-        Builder(
-          builder: (BuildContext context) {
-            return PlatformWebViewWidget(
-              PlatformWebViewWidgetCreationParams(controller: controller),
-            ).build(context);
-          },
-        ),
-      );
+      await tester.pumpWidget(Builder(
+        builder: (BuildContext context) {
+          return PlatformWebViewWidget(
+            PlatformWebViewWidgetCreationParams(controller: controller),
+          ).build(context);
+        },
+      ));
 
       await pageLoaded.future;
 
@@ -525,15 +584,13 @@
           ),
         );
 
-      await tester.pumpWidget(
-        Builder(
-          builder: (BuildContext context) {
-            return PlatformWebViewWidget(
-              PlatformWebViewWidgetCreationParams(controller: controller),
-            ).build(context);
-          },
-        ),
-      );
+      await tester.pumpWidget(Builder(
+        builder: (BuildContext context) {
+          return PlatformWebViewWidget(
+            PlatformWebViewWidgetCreationParams(controller: controller),
+          ).build(context);
+        },
+      ));
 
       await pageLoaded.future;
 
@@ -573,15 +630,13 @@
         ),
       );
 
-    await tester.pumpWidget(
-      Builder(
-        builder: (BuildContext context) {
-          return PlatformWebViewWidget(
-            PlatformWebViewWidgetCreationParams(controller: controller),
-          ).build(context);
-        },
-      ),
-    );
+    await tester.pumpWidget(Builder(
+      builder: (BuildContext context) {
+        return PlatformWebViewWidget(
+          PlatformWebViewWidgetCreationParams(controller: controller),
+        ).build(context);
+      },
+    ));
 
     await pageLoaded.future;
 
diff --git a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_controller.dart b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_controller.dart
index 6f4af3e..fd287a5 100644
--- a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_controller.dart
+++ b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_controller.dart
@@ -96,18 +96,20 @@
   );
 
   late final android_webview.WebChromeClient _webChromeClient =
-      withWeakReferenceTo(this,
-          (WeakReference<AndroidWebViewController> weakReference) {
-    return _androidWebViewParams.androidWebViewProxy
-        .createAndroidWebChromeClient(
-      onProgressChanged: (android_webview.WebView webView, int progress) {
-        if (weakReference.target?._currentNavigationDelegate._onProgress !=
+      _androidWebViewParams.androidWebViewProxy.createAndroidWebChromeClient(
+    onProgressChanged: withWeakReferenceTo(this,
+        (WeakReference<AndroidWebViewController> weakReference) {
+      return (android_webview.WebView webView, int progress) {
+        if (weakReference.target?._currentNavigationDelegate?._onProgress !=
             null) {
           weakReference
-              .target!._currentNavigationDelegate._onProgress!(progress);
+              .target!._currentNavigationDelegate!._onProgress!(progress);
         }
-      },
-      onShowFileChooser: (android_webview.WebView webView,
+      };
+    }),
+    onShowFileChooser: withWeakReferenceTo(this,
+        (WeakReference<AndroidWebViewController> weakReference) {
+      return (android_webview.WebView webView,
           android_webview.FileChooserParams params) async {
         if (weakReference.target?._onShowFileSelectorCallback != null) {
           return weakReference.target!._onShowFileSelectorCallback!(
@@ -115,9 +117,9 @@
           );
         }
         return <String>[];
-      },
-    );
-  });
+      };
+    }),
+  );
 
   /// The native [android_webview.FlutterAssetManager] allows managing assets.
   late final android_webview.FlutterAssetManager _flutterAssetManager =
@@ -126,10 +128,7 @@
   final Map<String, AndroidJavaScriptChannelParams> _javaScriptChannelParams =
       <String, AndroidJavaScriptChannelParams>{};
 
-  // The keeps a reference to the current NavigationDelegate so that the
-  // callback methods remain reachable.
-  // ignore: unused_field
-  late AndroidNavigationDelegate _currentNavigationDelegate;
+  AndroidNavigationDelegate? _currentNavigationDelegate;
 
   Future<List<String>> Function(FileSelectorParams)?
       _onShowFileSelectorCallback;
diff --git a/packages/webview_flutter/webview_flutter_android/pubspec.yaml b/packages/webview_flutter/webview_flutter_android/pubspec.yaml
index 81255df..30ea5d7 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: 3.2.2
+version: 3.2.3
 
 environment:
   sdk: ">=2.17.0 <3.0.0"
diff --git a/packages/webview_flutter/webview_flutter_android/test/android_webview_controller_test.dart b/packages/webview_flutter/webview_flutter_android/test/android_webview_controller_test.dart
index 80fa192..03e71ec 100644
--- a/packages/webview_flutter/webview_flutter_android/test/android_webview_controller_test.dart
+++ b/packages/webview_flutter/webview_flutter_android/test/android_webview_controller_test.dart
@@ -539,6 +539,19 @@
       expect(callbackProgress, 42);
     });
 
+    test('onProgress does not cause LateInitializationError', () {
+      // ignore: unused_local_variable
+      final AndroidWebViewController controller = createControllerWithMocks(
+        createWebChromeClient: CapturingWebChromeClient.new,
+      );
+
+      // Should not cause LateInitializationError
+      CapturingWebChromeClient.lastCreatedDelegate.onProgressChanged!(
+        android_webview.WebView.detached(),
+        42,
+      );
+    });
+
     test('setOnShowFileSelector', () async {
       late final Future<List<String>> Function(
         android_webview.WebView webView,
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/CHANGELOG.md b/packages/webview_flutter/webview_flutter_wkwebview/CHANGELOG.md
index a9cb87f..f79058c 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/CHANGELOG.md
+++ b/packages/webview_flutter/webview_flutter_wkwebview/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 3.0.4
+
+* Fixes bug that prevented the web view from being garbage collected.
+
 ## 3.0.3
 
 * Updates example code for `use_build_context_synchronously` lint.
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/example/integration_test/webview_flutter_test.dart b/packages/webview_flutter/webview_flutter_wkwebview/example/integration_test/webview_flutter_test.dart
index 946f27b..16411b8 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/example/integration_test/webview_flutter_test.dart
+++ b/packages/webview_flutter/webview_flutter_wkwebview/example/integration_test/webview_flutter_test.dart
@@ -21,6 +21,7 @@
 import 'package:webview_flutter_platform_interface/webview_flutter_platform_interface.dart';
 import 'package:webview_flutter_wkwebview/src/common/instance_manager.dart';
 import 'package:webview_flutter_wkwebview/src/common/weak_reference_utils.dart';
+import 'package:webview_flutter_wkwebview/src/web_kit/web_kit.dart';
 import 'package:webview_flutter_wkwebview/webview_flutter_wkwebview.dart';
 
 Future<void> main() async {
@@ -47,7 +48,7 @@
   final String headersUrl = '$prefixUrl/headers';
 
   testWidgets(
-      'withWeakRefenceTo allows encapsulating class to be garbage collected',
+      'withWeakReferenceTo allows encapsulating class to be garbage collected',
       (WidgetTester tester) async {
     final Completer<int> gcCompleter = Completer<int>();
     final InstanceManager instanceManager = InstanceManager(
@@ -68,21 +69,102 @@
     expect(gcIdentifier, 0);
   }, timeout: const Timeout(Duration(seconds: 10)));
 
+  testWidgets(
+    'WKWebView is released by garbage collection',
+    (WidgetTester tester) async {
+      final Completer<void> webViewGCCompleter = Completer<void>();
+
+      late final InstanceManager instanceManager;
+      instanceManager =
+          InstanceManager(onWeakReferenceRemoved: (int identifier) {
+        final Copyable instance =
+            instanceManager.getInstanceWithWeakReference(identifier)!;
+        if (instance is WKWebView && !webViewGCCompleter.isCompleted) {
+          webViewGCCompleter.complete();
+        }
+      });
+
+      await tester.pumpWidget(
+        Builder(
+          builder: (BuildContext context) {
+            return PlatformWebViewWidget(
+              WebKitWebViewWidgetCreationParams(
+                instanceManager: instanceManager,
+                controller: PlatformWebViewController(
+                  WebKitWebViewControllerCreationParams(
+                    instanceManager: instanceManager,
+                  ),
+                ),
+              ),
+            ).build(context);
+          },
+        ),
+      );
+      await tester.pumpAndSettle();
+
+      await tester.pumpWidget(Container());
+
+      // Force garbage collection.
+      await IntegrationTestWidgetsFlutterBinding.instance
+          .watchPerformance(() async {
+        await tester.pumpAndSettle();
+      });
+
+      await expectLater(webViewGCCompleter.future, completes);
+    },
+    timeout: const Timeout(Duration(seconds: 10)),
+  );
+
   testWidgets('loadRequest', (WidgetTester tester) async {
+    final Completer<void> pageFinished = Completer<void>();
+
     final PlatformWebViewController controller = PlatformWebViewController(
       const PlatformWebViewControllerCreationParams(),
-    );
-    controller.loadRequest(LoadRequestParams(uri: Uri.parse(primaryUrl)));
+    )
+      ..setPlatformNavigationDelegate(
+        PlatformNavigationDelegate(
+          const PlatformNavigationDelegateCreationParams(),
+        )..setOnPageFinished((_) => pageFinished.complete()),
+      )
+      ..loadRequest(LoadRequestParams(uri: Uri.parse(primaryUrl)));
+
+    await tester.pumpWidget(Builder(
+      builder: (BuildContext context) {
+        return PlatformWebViewWidget(
+          PlatformWebViewWidgetCreationParams(controller: controller),
+        ).build(context);
+      },
+    ));
+
+    await pageFinished.future;
 
     final String? currentUrl = await controller.currentUrl();
     expect(currentUrl, primaryUrl);
   });
 
   testWidgets('runJavaScriptReturningResult', (WidgetTester tester) async {
+    final Completer<void> pageFinished = Completer<void>();
+
     final PlatformWebViewController controller = PlatformWebViewController(
       const PlatformWebViewControllerCreationParams(),
-    );
-    controller.loadRequest(LoadRequestParams(uri: Uri.parse(primaryUrl)));
+    )
+      ..setJavaScriptMode(JavaScriptMode.unrestricted)
+      ..setPlatformNavigationDelegate(
+        PlatformNavigationDelegate(
+          const PlatformNavigationDelegateCreationParams(),
+        )..setOnPageFinished((_) => pageFinished.complete()),
+      )
+      ..loadRequest(LoadRequestParams(uri: Uri.parse(primaryUrl)));
+
+    await tester.pumpWidget(Builder(
+      builder: (BuildContext context) {
+        return PlatformWebViewWidget(
+          PlatformWebViewWidgetCreationParams(controller: controller),
+        ).build(context);
+      },
+    ));
+
+    await pageFinished.future;
 
     await expectLater(
       controller.runJavaScriptReturningResult('1 + 1'),
@@ -113,6 +195,14 @@
         ),
       );
 
+    await tester.pumpWidget(Builder(
+      builder: (BuildContext context) {
+        return PlatformWebViewWidget(
+          PlatformWebViewWidgetCreationParams(controller: controller),
+        ).build(context);
+      },
+    ));
+
     await pageLoads.stream.firstWhere((String url) => url == headersUrl);
 
     final String content = await controller.runJavaScriptReturningResult(
@@ -147,6 +237,14 @@
       'data:text/html;charset=utf-8;base64,PCFET0NUWVBFIGh0bWw+',
     );
 
+    await tester.pumpWidget(Builder(
+      builder: (BuildContext context) {
+        return PlatformWebViewWidget(
+          PlatformWebViewWidgetCreationParams(controller: controller),
+        ).build(context);
+      },
+    ));
+
     await pageFinished.future;
 
     await controller.runJavaScript('Echo.postMessage("hello");');
@@ -184,6 +282,14 @@
       ..setJavaScriptMode(JavaScriptMode.unrestricted)
       ..setUserAgent('Custom_User_Agent1');
 
+    await tester.pumpWidget(Builder(
+      builder: (BuildContext context) {
+        return PlatformWebViewWidget(
+          PlatformWebViewWidgetCreationParams(controller: controller),
+        ).build(context);
+      },
+    ));
+
     final String customUserAgent2 = await _getUserAgent(controller);
     expect(customUserAgent2, 'Custom_User_Agent1');
   });
@@ -250,6 +356,14 @@
           ),
         );
 
+      await tester.pumpWidget(Builder(
+        builder: (BuildContext context) {
+          return PlatformWebViewWidget(
+            PlatformWebViewWidgetCreationParams(controller: controller),
+          ).build(context);
+        },
+      ));
+
       await pageLoaded.future;
 
       bool isPaused =
@@ -274,6 +388,14 @@
           ),
         );
 
+      await tester.pumpWidget(Builder(
+        builder: (BuildContext context) {
+          return PlatformWebViewWidget(
+            PlatformWebViewWidgetCreationParams(controller: controller),
+          ).build(context);
+        },
+      ));
+
       await pageLoaded.future;
 
       isPaused =
@@ -447,6 +569,14 @@
           ),
         );
 
+      await tester.pumpWidget(Builder(
+        builder: (BuildContext context) {
+          return PlatformWebViewWidget(
+            PlatformWebViewWidgetCreationParams(controller: controller),
+          ).build(context);
+        },
+      ));
+
       await pageLoaded.future;
 
       bool isPaused =
@@ -471,6 +601,14 @@
           ),
         );
 
+      await tester.pumpWidget(Builder(
+        builder: (BuildContext context) {
+          return PlatformWebViewWidget(
+            PlatformWebViewWidgetCreationParams(controller: controller),
+          ).build(context);
+        },
+      ));
+
       await pageLoaded.future;
 
       isPaused =
@@ -509,6 +647,14 @@
         ),
       );
 
+    await tester.pumpWidget(Builder(
+      builder: (BuildContext context) {
+        return PlatformWebViewWidget(
+          PlatformWebViewWidgetCreationParams(controller: controller),
+        ).build(context);
+      },
+    ));
+
     await pageLoaded.future;
 
     // On at least iOS, it does not appear to be guaranteed that the native
@@ -565,6 +711,14 @@
           ),
         );
 
+      await tester.pumpWidget(Builder(
+        builder: (BuildContext context) {
+          return PlatformWebViewWidget(
+            PlatformWebViewWidgetCreationParams(controller: controller),
+          ).build(context);
+        },
+      ));
+
       await pageLoaded.future;
 
       await tester.pumpAndSettle(const Duration(seconds: 3));
@@ -599,8 +753,7 @@
         '${base64Encode(const Utf8Encoder().convert(blankPage))}';
 
     testWidgets('can allow requests', (WidgetTester tester) async {
-      final StreamController<String> pageLoads =
-          StreamController<String>.broadcast();
+      Completer<void> pageLoaded = Completer<void>();
 
       final PlatformWebViewController controller = PlatformWebViewController(
         WebKitWebViewControllerCreationParams(),
@@ -610,7 +763,7 @@
           WebKitNavigationDelegate(
             const WebKitNavigationDelegateCreationParams(),
           )
-            ..setOnPageFinished((String url) => pageLoads.add(url))
+            ..setOnPageFinished((_) => pageLoaded.complete())
             ..setOnNavigationRequest((NavigationRequest navigationRequest) {
               return (navigationRequest.url.contains('youtube.com'))
                   ? NavigationDecision.prevent
@@ -621,10 +774,20 @@
           LoadRequestParams(uri: Uri.parse(blankPageEncoded)),
         );
 
-      await pageLoads.stream.first; // Wait for initial page load.
-      await controller.runJavaScript('location.href = "$secondaryUrl"');
+      await tester.pumpWidget(Builder(
+        builder: (BuildContext context) {
+          return PlatformWebViewWidget(
+            PlatformWebViewWidgetCreationParams(controller: controller),
+          ).build(context);
+        },
+      ));
 
-      await pageLoads.stream.first; // Wait for the next page load.
+      await pageLoaded.future; // Wait for initial page load.
+
+      pageLoaded = Completer<void>();
+      await controller.runJavaScript('location.href = "$secondaryUrl"');
+      await pageLoaded.future;
+
       final String? currentUrl = await controller.currentUrl();
       expect(currentUrl, secondaryUrl);
     });
@@ -633,7 +796,7 @@
       final Completer<WebResourceError> errorCompleter =
           Completer<WebResourceError>();
 
-      PlatformWebViewController(
+      final PlatformWebViewController controller = PlatformWebViewController(
         WebKitWebViewControllerCreationParams(),
       )
         ..setJavaScriptMode(JavaScriptMode.unrestricted)
@@ -648,6 +811,14 @@
           LoadRequestParams(uri: Uri.parse('https://www.notawebsite..com')),
         );
 
+      await tester.pumpWidget(Builder(
+        builder: (BuildContext context) {
+          return PlatformWebViewWidget(
+            PlatformWebViewWidgetCreationParams(controller: controller),
+          ).build(context);
+        },
+      ));
+
       final WebResourceError error = await errorCompleter.future;
       expect(error, isNotNull);
 
@@ -660,7 +831,7 @@
           Completer<WebResourceError>();
       final Completer<void> pageFinishCompleter = Completer<void>();
 
-      PlatformWebViewController(
+      final PlatformWebViewController controller = PlatformWebViewController(
         WebKitWebViewControllerCreationParams(),
       )
         ..setJavaScriptMode(JavaScriptMode.unrestricted)
@@ -681,6 +852,14 @@
           ),
         );
 
+      await tester.pumpWidget(Builder(
+        builder: (BuildContext context) {
+          return PlatformWebViewWidget(
+            PlatformWebViewWidgetCreationParams(controller: controller),
+          ).build(context);
+        },
+      ));
+
       expect(errorCompleter.future, doesNotComplete);
       await pageFinishCompleter.future;
     });
@@ -706,7 +885,7 @@
             Completer<WebResourceError>();
         final Completer<void> pageFinishCompleter = Completer<void>();
 
-        PlatformWebViewController(
+        final PlatformWebViewController controller = PlatformWebViewController(
           WebKitWebViewControllerCreationParams(),
         )
           ..setJavaScriptMode(JavaScriptMode.unrestricted)
@@ -727,14 +906,21 @@
             ),
           );
 
+        await tester.pumpWidget(Builder(
+          builder: (BuildContext context) {
+            return PlatformWebViewWidget(
+              PlatformWebViewWidgetCreationParams(controller: controller),
+            ).build(context);
+          },
+        ));
+
         expect(errorCompleter.future, doesNotComplete);
         await pageFinishCompleter.future;
       },
     );
 
     testWidgets('can block requests', (WidgetTester tester) async {
-      final StreamController<String> pageLoads =
-          StreamController<String>.broadcast();
+      Completer<void> pageLoaded = Completer<void>();
 
       final PlatformWebViewController controller = PlatformWebViewController(
         WebKitWebViewControllerCreationParams(),
@@ -744,7 +930,7 @@
           WebKitNavigationDelegate(
             const WebKitNavigationDelegateCreationParams(),
           )
-            ..setOnPageFinished((String url) => pageLoads.add(url))
+            ..setOnPageFinished((_) => pageLoaded.complete())
             ..setOnNavigationRequest((NavigationRequest navigationRequest) {
               return (navigationRequest.url.contains('youtube.com'))
                   ? NavigationDecision.prevent
@@ -753,22 +939,31 @@
         )
         ..loadRequest(LoadRequestParams(uri: Uri.parse(blankPageEncoded)));
 
-      await pageLoads.stream.first; // Wait for initial page load.
+      await tester.pumpWidget(Builder(
+        builder: (BuildContext context) {
+          return PlatformWebViewWidget(
+            PlatformWebViewWidgetCreationParams(controller: controller),
+          ).build(context);
+        },
+      ));
+
+      await pageLoaded.future; // Wait for initial page load.
+
+      pageLoaded = Completer<void>();
       await controller
           .runJavaScript('location.href = "https://www.youtube.com/"');
 
       // There should never be any second page load, since our new URL is
       // blocked. Still wait for a potential page change for some time in order
       // to give the test a chance to fail.
-      await pageLoads.stream.first
+      await pageLoaded.future
           .timeout(const Duration(milliseconds: 500), onTimeout: () => '');
       final String? currentUrl = await controller.currentUrl();
       expect(currentUrl, isNot(contains('youtube.com')));
     });
 
     testWidgets('supports asynchronous decisions', (WidgetTester tester) async {
-      final StreamController<String> pageLoads =
-          StreamController<String>.broadcast();
+      Completer<void> pageLoaded = Completer<void>();
 
       final PlatformWebViewController controller = PlatformWebViewController(
         WebKitWebViewControllerCreationParams(),
@@ -778,7 +973,7 @@
           WebKitNavigationDelegate(
             const WebKitNavigationDelegateCreationParams(),
           )
-            ..setOnPageFinished((String url) => pageLoads.add(url))
+            ..setOnPageFinished((_) => pageLoaded.complete())
             ..setOnNavigationRequest(
                 (NavigationRequest navigationRequest) async {
               NavigationDecision decision = NavigationDecision.prevent;
@@ -790,10 +985,20 @@
         )
         ..loadRequest(LoadRequestParams(uri: Uri.parse(blankPageEncoded)));
 
-      await pageLoads.stream.first; // Wait for initial page load.
+      await tester.pumpWidget(Builder(
+        builder: (BuildContext context) {
+          return PlatformWebViewWidget(
+            PlatformWebViewWidgetCreationParams(controller: controller),
+          ).build(context);
+        },
+      ));
+
+      await pageLoaded.future; // Wait for initial page load.
+
+      pageLoaded = Completer<void>();
       await controller.runJavaScript('location.href = "$secondaryUrl"');
 
-      await pageLoads.stream.first; // Wait for second page to load.
+      await pageLoaded.future; // Wait for second page to load.
       final String? currentUrl = await controller.currentUrl();
       expect(currentUrl, secondaryUrl);
     });
@@ -807,6 +1012,14 @@
       ..setAllowsBackForwardNavigationGestures(true)
       ..loadRequest(LoadRequestParams(uri: Uri.parse(primaryUrl)));
 
+    await tester.pumpWidget(Builder(
+      builder: (BuildContext context) {
+        return PlatformWebViewWidget(
+          PlatformWebViewWidgetCreationParams(controller: controller),
+        ).build(context);
+      },
+    ));
+
     final String? currentUrl = await controller.currentUrl();
     expect(currentUrl, primaryUrl);
   });
@@ -824,6 +1037,15 @@
       )..setOnPageFinished((_) => pageLoaded.complete()));
 
     await controller.runJavaScript('window.open("$primaryUrl", "_blank")');
+
+    await tester.pumpWidget(Builder(
+      builder: (BuildContext context) {
+        return PlatformWebViewWidget(
+          PlatformWebViewWidgetCreationParams(controller: controller),
+        ).build(context);
+      },
+    ));
+
     await pageLoaded.future;
     final String? currentUrl = await controller.currentUrl();
     expect(currentUrl, primaryUrl);
@@ -843,6 +1065,14 @@
         )..setOnPageFinished((_) => pageLoaded.complete()))
         ..loadRequest(LoadRequestParams(uri: Uri.parse(primaryUrl)));
 
+      await tester.pumpWidget(Builder(
+        builder: (BuildContext context) {
+          return PlatformWebViewWidget(
+            PlatformWebViewWidgetCreationParams(controller: controller),
+          ).build(context);
+        },
+      ));
+
       expect(controller.currentUrl(), completion(primaryUrl));
       await pageLoaded.future;
       pageLoaded = Completer<void>();
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/lib/src/webkit_proxy.dart b/packages/webview_flutter/webview_flutter_wkwebview/lib/src/webkit_proxy.dart
index 2cdc7e2..3e8d679 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/lib/src/webkit_proxy.dart
+++ b/packages/webview_flutter/webview_flutter_wkwebview/lib/src/webkit_proxy.dart
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import 'common/instance_manager.dart';
 import 'foundation/foundation.dart';
 import 'web_kit/web_kit.dart';
 
@@ -39,10 +40,13 @@
       Map<NSKeyValueChangeKey, Object?> change,
     )?
         observeValue,
+    InstanceManager? instanceManager,
   }) createWebView;
 
   /// Constructs a [WKWebViewConfiguration].
-  final WKWebViewConfiguration Function() createWebViewConfiguration;
+  final WKWebViewConfiguration Function({
+    InstanceManager? instanceManager,
+  }) createWebViewConfiguration;
 
   /// Constructs a [WKScriptMessageHandler].
   final WKScriptMessageHandler Function({
@@ -72,7 +76,7 @@
     void Function(WKWebView webView)? webViewWebContentProcessDidTerminate,
   }) createNavigationDelegate;
 
-  /// Contructs a [WKUIDelegate].
+  /// Constructs a [WKUIDelegate].
   final WKUIDelegate Function({
     void Function(
       WKWebView webView,
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/lib/src/webkit_webview_controller.dart b/packages/webview_flutter/webview_flutter_wkwebview/lib/src/webkit_webview_controller.dart
index dc90906..02b5b73 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/lib/src/webkit_webview_controller.dart
+++ b/packages/webview_flutter/webview_flutter_wkwebview/lib/src/webkit_webview_controller.dart
@@ -49,7 +49,12 @@
       PlaybackMediaTypes.video,
     },
     this.allowsInlineMediaPlayback = false,
-  }) : _configuration = webKitProxy.createWebViewConfiguration() {
+    @visibleForTesting InstanceManager? instanceManager,
+  }) : _instanceManager = instanceManager ?? NSObject.globalInstanceManager {
+    _configuration = webKitProxy.createWebViewConfiguration(
+      instanceManager: _instanceManager,
+    );
+
     if (mediaTypesRequiringUserAction.isEmpty) {
       _configuration.setMediaTypesRequiringUserActionForPlayback(
         <WKAudiovisualMediaType>{WKAudiovisualMediaType.none},
@@ -79,13 +84,15 @@
       PlaybackMediaTypes.video,
     },
     bool allowsInlineMediaPlayback = false,
+    @visibleForTesting InstanceManager? instanceManager,
   }) : this(
           webKitProxy: webKitProxy,
           mediaTypesRequiringUserAction: mediaTypesRequiringUserAction,
           allowsInlineMediaPlayback: allowsInlineMediaPlayback,
+          instanceManager: instanceManager,
         );
 
-  final WKWebViewConfiguration _configuration;
+  late final WKWebViewConfiguration _configuration;
 
   /// Media types that require a user gesture to begin playing.
   ///
@@ -102,6 +109,10 @@
   /// native library.
   @visibleForTesting
   final WebKitProxy webKitProxy;
+
+  // Maintains instances used to communicate with the native objects they
+  // represent.
+  final InstanceManager _instanceManager;
 }
 
 /// An implementation of [PlatformWebViewController] with the WebKit api.
@@ -122,12 +133,12 @@
   }
 
   /// The WebKit WebView being controlled.
-  late final WKWebView _webView = withWeakRefenceTo(this, (
-    WeakReference<WebKitWebViewController> weakReference,
-  ) {
-    return _webKitParams.webKitProxy.createWebView(
-      _webKitParams._configuration,
-      observeValue: (
+  late final WKWebView _webView = _webKitParams.webKitProxy.createWebView(
+    _webKitParams._configuration,
+    observeValue: withWeakRefenceTo(this, (
+      WeakReference<WebKitWebViewController> weakReference,
+    ) {
+      return (
         String keyPath,
         NSObject object,
         Map<NSKeyValueChangeKey, Object?> change,
@@ -139,9 +150,10 @@
               change[NSKeyValueChangeKey.newValue]! as double;
           progressCallback((progress * 100).round());
         }
-      },
-    );
-  });
+      };
+    }),
+    instanceManager: _webKitParams._instanceManager,
+  );
 
   final Map<String, WebKitJavaScriptChannelParams> _javaScriptChannelParams =
       <String, WebKitJavaScriptChannelParams>{};
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/pubspec.yaml b/packages/webview_flutter/webview_flutter_wkwebview/pubspec.yaml
index c41bce1..15e8ac5 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/pubspec.yaml
+++ b/packages/webview_flutter/webview_flutter_wkwebview/pubspec.yaml
@@ -2,7 +2,7 @@
 description: A Flutter plugin that provides a WebView widget based on Apple's WKWebView control.
 repository: https://github.com/flutter/plugins/tree/main/packages/webview_flutter/webview_flutter_wkwebview
 issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+webview%22
-version: 3.0.3
+version: 3.0.4
 
 environment:
   sdk: ">=2.17.0 <3.0.0"
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/test/webkit_webview_controller_test.dart b/packages/webview_flutter/webview_flutter_wkwebview/test/webkit_webview_controller_test.dart
index fc06db2..0360c13 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/test/webkit_webview_controller_test.dart
+++ b/packages/webview_flutter/webview_flutter_wkwebview/test/webkit_webview_controller_test.dart
@@ -13,6 +13,7 @@
 import 'package:mockito/annotations.dart';
 import 'package:mockito/mockito.dart';
 import 'package:webview_flutter_platform_interface/webview_flutter_platform_interface.dart';
+import 'package:webview_flutter_wkwebview/src/common/instance_manager.dart';
 import 'package:webview_flutter_wkwebview/src/foundation/foundation.dart';
 import 'package:webview_flutter_wkwebview/src/ui_kit/ui_kit.dart';
 import 'package:webview_flutter_wkwebview/src/web_kit/web_kit.dart';
@@ -49,6 +50,7 @@
       })?
           createMockWebView,
       MockWKWebViewConfiguration? mockWebViewConfiguration,
+      InstanceManager? instanceManager,
     }) {
       final MockWKWebViewConfiguration nonNullMockWebViewConfiguration =
           mockWebViewConfiguration ?? MockWKWebViewConfiguration();
@@ -57,7 +59,9 @@
       final PlatformWebViewControllerCreationParams controllerCreationParams =
           WebKitWebViewControllerCreationParams(
         webKitProxy: WebKitProxy(
-          createWebViewConfiguration: () => nonNullMockWebViewConfiguration,
+          createWebViewConfiguration: ({InstanceManager? instanceManager}) {
+            return nonNullMockWebViewConfiguration;
+          },
           createWebView: (
             _, {
             void Function(
@@ -66,6 +70,7 @@
               Map<NSKeyValueChangeKey, Object?> change,
             )?
                 observeValue,
+            InstanceManager? instanceManager,
           }) {
             nonNullMockWebView = createMockWebView == null
                 ? MockWKWebView()
@@ -104,7 +109,9 @@
 
         WebKitWebViewControllerCreationParams(
           webKitProxy: WebKitProxy(
-            createWebViewConfiguration: () => mockConfiguration,
+            createWebViewConfiguration: ({InstanceManager? instanceManager}) {
+              return mockConfiguration;
+            },
           ),
           allowsInlineMediaPlayback: true,
         );
@@ -120,7 +127,9 @@
 
         WebKitWebViewControllerCreationParams(
           webKitProxy: WebKitProxy(
-            createWebViewConfiguration: () => mockConfiguration,
+            createWebViewConfiguration: ({InstanceManager? instanceManager}) {
+              return mockConfiguration;
+            },
           ),
           mediaTypesRequiringUserAction: const <PlaybackMediaTypes>{
             PlaybackMediaTypes.video,
@@ -143,7 +152,9 @@
 
         WebKitWebViewControllerCreationParams(
           webKitProxy: WebKitProxy(
-            createWebViewConfiguration: () => mockConfiguration,
+            createWebViewConfiguration: ({InstanceManager? instanceManager}) {
+              return mockConfiguration;
+            },
           ),
         );
 
@@ -164,7 +175,9 @@
 
         WebKitWebViewControllerCreationParams(
           webKitProxy: WebKitProxy(
-            createWebViewConfiguration: () => mockConfiguration,
+            createWebViewConfiguration: ({InstanceManager? instanceManager}) {
+              return mockConfiguration;
+            },
           ),
           mediaTypesRequiringUserAction: const <PlaybackMediaTypes>{},
         );
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/test/webkit_webview_widget_test.dart b/packages/webview_flutter/webview_flutter_wkwebview/test/webkit_webview_widget_test.dart
index 2e0d6e3..2a6434b 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/test/webkit_webview_widget_test.dart
+++ b/packages/webview_flutter/webview_flutter_wkwebview/test/webkit_webview_widget_test.dart
@@ -19,7 +19,7 @@
 
   group('WebKitWebViewWidget', () {
     testWidgets('build', (WidgetTester tester) async {
-      final InstanceManager instanceManager = InstanceManager(
+      final InstanceManager testInstanceManager = InstanceManager(
         onWeakReferenceRemoved: (_) {},
       );
 
@@ -34,14 +34,17 @@
                 Map<NSKeyValueChangeKey, Object?> change,
               )?
                   observeValue,
+              InstanceManager? instanceManager,
             }) {
               final WKWebView webView = WKWebView.detached(
-                instanceManager: instanceManager,
+                instanceManager: testInstanceManager,
               );
-              instanceManager.addDartCreatedInstance(webView);
+              testInstanceManager.addDartCreatedInstance(webView);
               return webView;
             },
-            createWebViewConfiguration: () => MockWKWebViewConfiguration(),
+            createWebViewConfiguration: ({InstanceManager? instanceManager}) {
+              return MockWKWebViewConfiguration();
+            },
           ),
         ),
       );
@@ -50,7 +53,7 @@
         WebKitWebViewWidgetCreationParams(
           key: const Key('keyValue'),
           controller: controller,
-          instanceManager: instanceManager,
+          instanceManager: testInstanceManager,
         ),
       );