[webview_flutter_android] [webview_flutter_wkwebview] Adds support for `PlatformNavigationDelegate.onUrlChange` (#3653)

[webview_flutter_android] [webview_flutter_wkwebview] Adds support for `PlatformNavigationDelegate.onUrlChange`
diff --git a/packages/webview_flutter/webview_flutter_android/CHANGELOG.md b/packages/webview_flutter/webview_flutter_android/CHANGELOG.md
index 953ec4d..abdeece 100644
--- a/packages/webview_flutter/webview_flutter_android/CHANGELOG.md
+++ b/packages/webview_flutter/webview_flutter_android/CHANGELOG.md
@@ -1,5 +1,6 @@
-## NEXT
+## 3.5.0
 
+* Adds support for `PlatformNavigationDelegate.onUrlChange`.
 * Bumps androidx.webkit:webkit from 1.6.0 to 1.6.1.
 * Fixes common typos in tests and documentation.
 
diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/GeneratedAndroidWebView.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/GeneratedAndroidWebView.java
index 507c07a..5f26060 100644
--- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/GeneratedAndroidWebView.java
+++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/GeneratedAndroidWebView.java
@@ -1,7 +1,7 @@
 // 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.
-// Autogenerated from Pigeon (v9.0.5), do not edit directly.
+// Autogenerated from Pigeon (v9.2.3), do not edit directly.
 // See also: https://pub.dev/packages/pigeon
 
 package io.flutter.plugins.webviewflutter;
@@ -22,15 +22,39 @@
 import java.util.Map;
 
 /** Generated class from Pigeon. */
-@SuppressWarnings({"unused", "unchecked", "CodeBlock2Expr", "RedundantSuppression"})
+@SuppressWarnings({"unused", "unchecked", "CodeBlock2Expr", "RedundantSuppression", "serial"})
 public class GeneratedAndroidWebView {
+
+  /** Error class for passing custom error details to Flutter via a thrown PlatformException. */
+  public static class FlutterError extends RuntimeException {
+
+    /** The error code. */
+    public final String code;
+
+    /** The error details. Must be a datatype supported by the api codec. */
+    public final Object details;
+
+    public FlutterError(@NonNull String code, @Nullable String message, @Nullable Object details) {
+      super(message);
+      this.code = code;
+      this.details = details;
+    }
+  }
+
   @NonNull
-  private static ArrayList<Object> wrapError(@NonNull Throwable exception) {
+  protected static ArrayList<Object> wrapError(@NonNull Throwable exception) {
     ArrayList<Object> errorList = new ArrayList<Object>(3);
-    errorList.add(exception.toString());
-    errorList.add(exception.getClass().getSimpleName());
-    errorList.add(
-        "Cause: " + exception.getCause() + ", Stacktrace: " + Log.getStackTraceString(exception));
+    if (exception instanceof FlutterError) {
+      FlutterError error = (FlutterError) exception;
+      errorList.add(error.code);
+      errorList.add(error.getMessage());
+      errorList.add(error.details);
+    } else {
+      errorList.add(exception.toString());
+      errorList.add(exception.getClass().getSimpleName());
+      errorList.add(
+          "Cause: " + exception.getCause() + ", Stacktrace: " + Log.getStackTraceString(exception));
+    }
     return errorList;
   }
 
@@ -63,7 +87,7 @@
      */
     SAVE(2);
 
-    private final int index;
+    final int index;
 
     private FileChooserMode(final int index) {
       this.index = index;
@@ -85,8 +109,8 @@
       this.value = setterArg;
     }
 
-    /** Constructor is private to enforce null safety; use Builder. */
-    private FileChooserModeEnumData() {}
+    /** Constructor is non-public to enforce null safety; use Builder. */
+    FileChooserModeEnumData() {}
 
     public static final class Builder {
 
@@ -196,8 +220,8 @@
       this.requestHeaders = setterArg;
     }
 
-    /** Constructor is private to enforce null safety; use Builder. */
-    private WebResourceRequestData() {}
+    /** Constructor is non-public to enforce null safety; use Builder. */
+    WebResourceRequestData() {}
 
     public static final class Builder {
 
@@ -313,8 +337,8 @@
       this.description = setterArg;
     }
 
-    /** Constructor is private to enforce null safety; use Builder. */
-    private WebResourceErrorData() {}
+    /** Constructor is non-public to enforce null safety; use Builder. */
+    WebResourceErrorData() {}
 
     public static final class Builder {
 
@@ -389,8 +413,8 @@
       this.y = setterArg;
     }
 
-    /** Constructor is private to enforce null safety; use Builder. */
-    private WebViewPoint() {}
+    /** Constructor is non-public to enforce null safety; use Builder. */
+    WebViewPoint() {}
 
     public static final class Builder {
 
@@ -435,9 +459,10 @@
   }
 
   public interface Result<T> {
+    @SuppressWarnings("UnknownNullness")
     void success(T result);
 
-    void error(Throwable error);
+    void error(@NonNull Throwable error);
   }
   /**
    * Host API for managing the native `InstanceManager`.
@@ -453,14 +478,15 @@
     void clear();
 
     /** The codec used by InstanceManagerHostApi. */
-    static MessageCodec<Object> getCodec() {
+    static @NonNull MessageCodec<Object> getCodec() {
       return new StandardMessageCodec();
     }
     /**
      * Sets up an instance of `InstanceManagerHostApi` to handle messages through the
      * `binaryMessenger`.
      */
-    static void setup(BinaryMessenger binaryMessenger, InstanceManagerHostApi api) {
+    static void setup(
+        @NonNull BinaryMessenger binaryMessenger, @Nullable InstanceManagerHostApi api) {
       {
         BasicMessageChannel<Object> channel =
             new BasicMessageChannel<>(
@@ -472,7 +498,7 @@
                 try {
                   api.clear();
                   wrapped.add(0, null);
-                } catch (Error | RuntimeException exception) {
+                } catch (Throwable exception) {
                   ArrayList<Object> wrappedError = wrapError(exception);
                   wrapped = wrappedError;
                 }
@@ -498,13 +524,13 @@
     void dispose(@NonNull Long identifier);
 
     /** The codec used by JavaObjectHostApi. */
-    static MessageCodec<Object> getCodec() {
+    static @NonNull MessageCodec<Object> getCodec() {
       return new StandardMessageCodec();
     }
     /**
      * Sets up an instance of `JavaObjectHostApi` to handle messages through the `binaryMessenger`.
      */
-    static void setup(BinaryMessenger binaryMessenger, JavaObjectHostApi api) {
+    static void setup(@NonNull BinaryMessenger binaryMessenger, @Nullable JavaObjectHostApi api) {
       {
         BasicMessageChannel<Object> channel =
             new BasicMessageChannel<>(
@@ -513,16 +539,12 @@
           channel.setMessageHandler(
               (message, reply) -> {
                 ArrayList<Object> wrapped = new ArrayList<Object>();
+                ArrayList<Object> args = (ArrayList<Object>) message;
+                Number identifierArg = (Number) args.get(0);
                 try {
-                  ArrayList<Object> args = (ArrayList<Object>) message;
-                  assert args != null;
-                  Number identifierArg = (Number) args.get(0);
-                  if (identifierArg == null) {
-                    throw new NullPointerException("identifierArg unexpectedly null.");
-                  }
                   api.dispose((identifierArg == null) ? null : identifierArg.longValue());
                   wrapped.add(0, null);
-                } catch (Error | RuntimeException exception) {
+                } catch (Throwable exception) {
                   ArrayList<Object> wrappedError = wrapError(exception);
                   wrapped = wrappedError;
                 }
@@ -542,22 +564,23 @@
    * <p>Generated class from Pigeon that represents Flutter messages that can be called from Java.
    */
   public static class JavaObjectFlutterApi {
-    private final BinaryMessenger binaryMessenger;
+    private final @NonNull BinaryMessenger binaryMessenger;
 
-    public JavaObjectFlutterApi(BinaryMessenger argBinaryMessenger) {
+    public JavaObjectFlutterApi(@NonNull BinaryMessenger argBinaryMessenger) {
       this.binaryMessenger = argBinaryMessenger;
     }
 
     /** Public interface for sending reply. */
+    @SuppressWarnings("UnknownNullness")
     public interface Reply<T> {
       void reply(T reply);
     }
     /** The codec used by JavaObjectFlutterApi. */
-    static MessageCodec<Object> getCodec() {
+    static @NonNull MessageCodec<Object> getCodec() {
       return new StandardMessageCodec();
     }
 
-    public void dispose(@NonNull Long identifierArg, Reply<Void> callback) {
+    public void dispose(@NonNull Long identifierArg, @NonNull Reply<Void> callback) {
       BasicMessageChannel<Object> channel =
           new BasicMessageChannel<>(
               binaryMessenger, "dev.flutter.pigeon.JavaObjectFlutterApi.dispose", getCodec());
@@ -569,19 +592,20 @@
   /** Generated interface from Pigeon that represents a handler of messages from Flutter. */
   public interface CookieManagerHostApi {
 
-    void clearCookies(Result<Boolean> result);
+    void clearCookies(@NonNull Result<Boolean> result);
 
     void setCookie(@NonNull String url, @NonNull String value);
 
     /** The codec used by CookieManagerHostApi. */
-    static MessageCodec<Object> getCodec() {
+    static @NonNull MessageCodec<Object> getCodec() {
       return new StandardMessageCodec();
     }
     /**
      * Sets up an instance of `CookieManagerHostApi` to handle messages through the
      * `binaryMessenger`.
      */
-    static void setup(BinaryMessenger binaryMessenger, CookieManagerHostApi api) {
+    static void setup(
+        @NonNull BinaryMessenger binaryMessenger, @Nullable CookieManagerHostApi api) {
       {
         BasicMessageChannel<Object> channel =
             new BasicMessageChannel<>(
@@ -592,25 +616,20 @@
           channel.setMessageHandler(
               (message, reply) -> {
                 ArrayList<Object> wrapped = new ArrayList<Object>();
-                try {
-                  Result<Boolean> resultCallback =
-                      new Result<Boolean>() {
-                        public void success(Boolean result) {
-                          wrapped.add(0, result);
-                          reply.reply(wrapped);
-                        }
+                Result<Boolean> resultCallback =
+                    new Result<Boolean>() {
+                      public void success(Boolean result) {
+                        wrapped.add(0, result);
+                        reply.reply(wrapped);
+                      }
 
-                        public void error(Throwable error) {
-                          ArrayList<Object> wrappedError = wrapError(error);
-                          reply.reply(wrappedError);
-                        }
-                      };
+                      public void error(Throwable error) {
+                        ArrayList<Object> wrappedError = wrapError(error);
+                        reply.reply(wrappedError);
+                      }
+                    };
 
-                  api.clearCookies(resultCallback);
-                } catch (Error | RuntimeException exception) {
-                  ArrayList<Object> wrappedError = wrapError(exception);
-                  reply.reply(wrappedError);
-                }
+                api.clearCookies(resultCallback);
               });
         } else {
           channel.setMessageHandler(null);
@@ -624,20 +643,13 @@
           channel.setMessageHandler(
               (message, reply) -> {
                 ArrayList<Object> wrapped = new ArrayList<Object>();
+                ArrayList<Object> args = (ArrayList<Object>) message;
+                String urlArg = (String) args.get(0);
+                String valueArg = (String) args.get(1);
                 try {
-                  ArrayList<Object> args = (ArrayList<Object>) message;
-                  assert args != null;
-                  String urlArg = (String) args.get(0);
-                  if (urlArg == null) {
-                    throw new NullPointerException("urlArg unexpectedly null.");
-                  }
-                  String valueArg = (String) args.get(1);
-                  if (valueArg == null) {
-                    throw new NullPointerException("valueArg unexpectedly null.");
-                  }
                   api.setCookie(urlArg, valueArg);
                   wrapped.add(0, null);
-                } catch (Error | RuntimeException exception) {
+                } catch (Throwable exception) {
                   ArrayList<Object> wrappedError = wrapError(exception);
                   wrapped = wrappedError;
                 }
@@ -718,7 +730,7 @@
     void clearCache(@NonNull Long instanceId, @NonNull Boolean includeDiskFiles);
 
     void evaluateJavascript(
-        @NonNull Long instanceId, @NonNull String javascriptString, Result<String> result);
+        @NonNull Long instanceId, @NonNull String javascriptString, @NonNull Result<String> result);
 
     @Nullable
     String getTitle(@NonNull Long instanceId);
@@ -752,11 +764,11 @@
     void setBackgroundColor(@NonNull Long instanceId, @NonNull Long color);
 
     /** The codec used by WebViewHostApi. */
-    static MessageCodec<Object> getCodec() {
+    static @NonNull MessageCodec<Object> getCodec() {
       return WebViewHostApiCodec.INSTANCE;
     }
     /** Sets up an instance of `WebViewHostApi` to handle messages through the `binaryMessenger`. */
-    static void setup(BinaryMessenger binaryMessenger, WebViewHostApi api) {
+    static void setup(@NonNull BinaryMessenger binaryMessenger, @Nullable WebViewHostApi api) {
       {
         BasicMessageChannel<Object> channel =
             new BasicMessageChannel<>(
@@ -765,16 +777,12 @@
           channel.setMessageHandler(
               (message, reply) -> {
                 ArrayList<Object> wrapped = new ArrayList<Object>();
+                ArrayList<Object> args = (ArrayList<Object>) message;
+                Number instanceIdArg = (Number) args.get(0);
                 try {
-                  ArrayList<Object> args = (ArrayList<Object>) message;
-                  assert args != null;
-                  Number instanceIdArg = (Number) args.get(0);
-                  if (instanceIdArg == null) {
-                    throw new NullPointerException("instanceIdArg unexpectedly null.");
-                  }
                   api.create((instanceIdArg == null) ? null : instanceIdArg.longValue());
                   wrapped.add(0, null);
-                } catch (Error | RuntimeException exception) {
+                } catch (Throwable exception) {
                   ArrayList<Object> wrappedError = wrapError(exception);
                   wrapped = wrappedError;
                 }
@@ -792,26 +800,19 @@
           channel.setMessageHandler(
               (message, reply) -> {
                 ArrayList<Object> wrapped = new ArrayList<Object>();
+                ArrayList<Object> args = (ArrayList<Object>) message;
+                Number instanceIdArg = (Number) args.get(0);
+                String dataArg = (String) args.get(1);
+                String mimeTypeArg = (String) args.get(2);
+                String encodingArg = (String) args.get(3);
                 try {
-                  ArrayList<Object> args = (ArrayList<Object>) message;
-                  assert args != null;
-                  Number instanceIdArg = (Number) args.get(0);
-                  if (instanceIdArg == null) {
-                    throw new NullPointerException("instanceIdArg unexpectedly null.");
-                  }
-                  String dataArg = (String) args.get(1);
-                  if (dataArg == null) {
-                    throw new NullPointerException("dataArg unexpectedly null.");
-                  }
-                  String mimeTypeArg = (String) args.get(2);
-                  String encodingArg = (String) args.get(3);
                   api.loadData(
                       (instanceIdArg == null) ? null : instanceIdArg.longValue(),
                       dataArg,
                       mimeTypeArg,
                       encodingArg);
                   wrapped.add(0, null);
-                } catch (Error | RuntimeException exception) {
+                } catch (Throwable exception) {
                   ArrayList<Object> wrappedError = wrapError(exception);
                   wrapped = wrappedError;
                 }
@@ -831,21 +832,14 @@
           channel.setMessageHandler(
               (message, reply) -> {
                 ArrayList<Object> wrapped = new ArrayList<Object>();
+                ArrayList<Object> args = (ArrayList<Object>) message;
+                Number instanceIdArg = (Number) args.get(0);
+                String baseUrlArg = (String) args.get(1);
+                String dataArg = (String) args.get(2);
+                String mimeTypeArg = (String) args.get(3);
+                String encodingArg = (String) args.get(4);
+                String historyUrlArg = (String) args.get(5);
                 try {
-                  ArrayList<Object> args = (ArrayList<Object>) message;
-                  assert args != null;
-                  Number instanceIdArg = (Number) args.get(0);
-                  if (instanceIdArg == null) {
-                    throw new NullPointerException("instanceIdArg unexpectedly null.");
-                  }
-                  String baseUrlArg = (String) args.get(1);
-                  String dataArg = (String) args.get(2);
-                  if (dataArg == null) {
-                    throw new NullPointerException("dataArg unexpectedly null.");
-                  }
-                  String mimeTypeArg = (String) args.get(3);
-                  String encodingArg = (String) args.get(4);
-                  String historyUrlArg = (String) args.get(5);
                   api.loadDataWithBaseUrl(
                       (instanceIdArg == null) ? null : instanceIdArg.longValue(),
                       baseUrlArg,
@@ -854,7 +848,7 @@
                       encodingArg,
                       historyUrlArg);
                   wrapped.add(0, null);
-                } catch (Error | RuntimeException exception) {
+                } catch (Throwable exception) {
                   ArrayList<Object> wrappedError = wrapError(exception);
                   wrapped = wrappedError;
                 }
@@ -872,27 +866,17 @@
           channel.setMessageHandler(
               (message, reply) -> {
                 ArrayList<Object> wrapped = new ArrayList<Object>();
+                ArrayList<Object> args = (ArrayList<Object>) message;
+                Number instanceIdArg = (Number) args.get(0);
+                String urlArg = (String) args.get(1);
+                Map<String, String> headersArg = (Map<String, String>) args.get(2);
                 try {
-                  ArrayList<Object> args = (ArrayList<Object>) message;
-                  assert args != null;
-                  Number instanceIdArg = (Number) args.get(0);
-                  if (instanceIdArg == null) {
-                    throw new NullPointerException("instanceIdArg unexpectedly null.");
-                  }
-                  String urlArg = (String) args.get(1);
-                  if (urlArg == null) {
-                    throw new NullPointerException("urlArg unexpectedly null.");
-                  }
-                  Map<String, String> headersArg = (Map<String, String>) args.get(2);
-                  if (headersArg == null) {
-                    throw new NullPointerException("headersArg unexpectedly null.");
-                  }
                   api.loadUrl(
                       (instanceIdArg == null) ? null : instanceIdArg.longValue(),
                       urlArg,
                       headersArg);
                   wrapped.add(0, null);
-                } catch (Error | RuntimeException exception) {
+                } catch (Throwable exception) {
                   ArrayList<Object> wrappedError = wrapError(exception);
                   wrapped = wrappedError;
                 }
@@ -910,25 +894,15 @@
           channel.setMessageHandler(
               (message, reply) -> {
                 ArrayList<Object> wrapped = new ArrayList<Object>();
+                ArrayList<Object> args = (ArrayList<Object>) message;
+                Number instanceIdArg = (Number) args.get(0);
+                String urlArg = (String) args.get(1);
+                byte[] dataArg = (byte[]) args.get(2);
                 try {
-                  ArrayList<Object> args = (ArrayList<Object>) message;
-                  assert args != null;
-                  Number instanceIdArg = (Number) args.get(0);
-                  if (instanceIdArg == null) {
-                    throw new NullPointerException("instanceIdArg unexpectedly null.");
-                  }
-                  String urlArg = (String) args.get(1);
-                  if (urlArg == null) {
-                    throw new NullPointerException("urlArg unexpectedly null.");
-                  }
-                  byte[] dataArg = (byte[]) args.get(2);
-                  if (dataArg == null) {
-                    throw new NullPointerException("dataArg unexpectedly null.");
-                  }
                   api.postUrl(
                       (instanceIdArg == null) ? null : instanceIdArg.longValue(), urlArg, dataArg);
                   wrapped.add(0, null);
-                } catch (Error | RuntimeException exception) {
+                } catch (Throwable exception) {
                   ArrayList<Object> wrappedError = wrapError(exception);
                   wrapped = wrappedError;
                 }
@@ -946,17 +920,13 @@
           channel.setMessageHandler(
               (message, reply) -> {
                 ArrayList<Object> wrapped = new ArrayList<Object>();
+                ArrayList<Object> args = (ArrayList<Object>) message;
+                Number instanceIdArg = (Number) args.get(0);
                 try {
-                  ArrayList<Object> args = (ArrayList<Object>) message;
-                  assert args != null;
-                  Number instanceIdArg = (Number) args.get(0);
-                  if (instanceIdArg == null) {
-                    throw new NullPointerException("instanceIdArg unexpectedly null.");
-                  }
                   String output =
                       api.getUrl((instanceIdArg == null) ? null : instanceIdArg.longValue());
                   wrapped.add(0, output);
-                } catch (Error | RuntimeException exception) {
+                } catch (Throwable exception) {
                   ArrayList<Object> wrappedError = wrapError(exception);
                   wrapped = wrappedError;
                 }
@@ -974,17 +944,13 @@
           channel.setMessageHandler(
               (message, reply) -> {
                 ArrayList<Object> wrapped = new ArrayList<Object>();
+                ArrayList<Object> args = (ArrayList<Object>) message;
+                Number instanceIdArg = (Number) args.get(0);
                 try {
-                  ArrayList<Object> args = (ArrayList<Object>) message;
-                  assert args != null;
-                  Number instanceIdArg = (Number) args.get(0);
-                  if (instanceIdArg == null) {
-                    throw new NullPointerException("instanceIdArg unexpectedly null.");
-                  }
                   Boolean output =
                       api.canGoBack((instanceIdArg == null) ? null : instanceIdArg.longValue());
                   wrapped.add(0, output);
-                } catch (Error | RuntimeException exception) {
+                } catch (Throwable exception) {
                   ArrayList<Object> wrappedError = wrapError(exception);
                   wrapped = wrappedError;
                 }
@@ -1002,17 +968,13 @@
           channel.setMessageHandler(
               (message, reply) -> {
                 ArrayList<Object> wrapped = new ArrayList<Object>();
+                ArrayList<Object> args = (ArrayList<Object>) message;
+                Number instanceIdArg = (Number) args.get(0);
                 try {
-                  ArrayList<Object> args = (ArrayList<Object>) message;
-                  assert args != null;
-                  Number instanceIdArg = (Number) args.get(0);
-                  if (instanceIdArg == null) {
-                    throw new NullPointerException("instanceIdArg unexpectedly null.");
-                  }
                   Boolean output =
                       api.canGoForward((instanceIdArg == null) ? null : instanceIdArg.longValue());
                   wrapped.add(0, output);
-                } catch (Error | RuntimeException exception) {
+                } catch (Throwable exception) {
                   ArrayList<Object> wrappedError = wrapError(exception);
                   wrapped = wrappedError;
                 }
@@ -1030,16 +992,12 @@
           channel.setMessageHandler(
               (message, reply) -> {
                 ArrayList<Object> wrapped = new ArrayList<Object>();
+                ArrayList<Object> args = (ArrayList<Object>) message;
+                Number instanceIdArg = (Number) args.get(0);
                 try {
-                  ArrayList<Object> args = (ArrayList<Object>) message;
-                  assert args != null;
-                  Number instanceIdArg = (Number) args.get(0);
-                  if (instanceIdArg == null) {
-                    throw new NullPointerException("instanceIdArg unexpectedly null.");
-                  }
                   api.goBack((instanceIdArg == null) ? null : instanceIdArg.longValue());
                   wrapped.add(0, null);
-                } catch (Error | RuntimeException exception) {
+                } catch (Throwable exception) {
                   ArrayList<Object> wrappedError = wrapError(exception);
                   wrapped = wrappedError;
                 }
@@ -1057,16 +1015,12 @@
           channel.setMessageHandler(
               (message, reply) -> {
                 ArrayList<Object> wrapped = new ArrayList<Object>();
+                ArrayList<Object> args = (ArrayList<Object>) message;
+                Number instanceIdArg = (Number) args.get(0);
                 try {
-                  ArrayList<Object> args = (ArrayList<Object>) message;
-                  assert args != null;
-                  Number instanceIdArg = (Number) args.get(0);
-                  if (instanceIdArg == null) {
-                    throw new NullPointerException("instanceIdArg unexpectedly null.");
-                  }
                   api.goForward((instanceIdArg == null) ? null : instanceIdArg.longValue());
                   wrapped.add(0, null);
-                } catch (Error | RuntimeException exception) {
+                } catch (Throwable exception) {
                   ArrayList<Object> wrappedError = wrapError(exception);
                   wrapped = wrappedError;
                 }
@@ -1084,16 +1038,12 @@
           channel.setMessageHandler(
               (message, reply) -> {
                 ArrayList<Object> wrapped = new ArrayList<Object>();
+                ArrayList<Object> args = (ArrayList<Object>) message;
+                Number instanceIdArg = (Number) args.get(0);
                 try {
-                  ArrayList<Object> args = (ArrayList<Object>) message;
-                  assert args != null;
-                  Number instanceIdArg = (Number) args.get(0);
-                  if (instanceIdArg == null) {
-                    throw new NullPointerException("instanceIdArg unexpectedly null.");
-                  }
                   api.reload((instanceIdArg == null) ? null : instanceIdArg.longValue());
                   wrapped.add(0, null);
-                } catch (Error | RuntimeException exception) {
+                } catch (Throwable exception) {
                   ArrayList<Object> wrappedError = wrapError(exception);
                   wrapped = wrappedError;
                 }
@@ -1111,22 +1061,15 @@
           channel.setMessageHandler(
               (message, reply) -> {
                 ArrayList<Object> wrapped = new ArrayList<Object>();
+                ArrayList<Object> args = (ArrayList<Object>) message;
+                Number instanceIdArg = (Number) args.get(0);
+                Boolean includeDiskFilesArg = (Boolean) args.get(1);
                 try {
-                  ArrayList<Object> args = (ArrayList<Object>) message;
-                  assert args != null;
-                  Number instanceIdArg = (Number) args.get(0);
-                  if (instanceIdArg == null) {
-                    throw new NullPointerException("instanceIdArg unexpectedly null.");
-                  }
-                  Boolean includeDiskFilesArg = (Boolean) args.get(1);
-                  if (includeDiskFilesArg == null) {
-                    throw new NullPointerException("includeDiskFilesArg unexpectedly null.");
-                  }
                   api.clearCache(
                       (instanceIdArg == null) ? null : instanceIdArg.longValue(),
                       includeDiskFilesArg);
                   wrapped.add(0, null);
-                } catch (Error | RuntimeException exception) {
+                } catch (Throwable exception) {
                   ArrayList<Object> wrappedError = wrapError(exception);
                   wrapped = wrappedError;
                 }
@@ -1146,38 +1089,26 @@
           channel.setMessageHandler(
               (message, reply) -> {
                 ArrayList<Object> wrapped = new ArrayList<Object>();
-                try {
-                  ArrayList<Object> args = (ArrayList<Object>) message;
-                  assert args != null;
-                  Number instanceIdArg = (Number) args.get(0);
-                  if (instanceIdArg == null) {
-                    throw new NullPointerException("instanceIdArg unexpectedly null.");
-                  }
-                  String javascriptStringArg = (String) args.get(1);
-                  if (javascriptStringArg == null) {
-                    throw new NullPointerException("javascriptStringArg unexpectedly null.");
-                  }
-                  Result<String> resultCallback =
-                      new Result<String>() {
-                        public void success(String result) {
-                          wrapped.add(0, result);
-                          reply.reply(wrapped);
-                        }
+                ArrayList<Object> args = (ArrayList<Object>) message;
+                Number instanceIdArg = (Number) args.get(0);
+                String javascriptStringArg = (String) args.get(1);
+                Result<String> resultCallback =
+                    new Result<String>() {
+                      public void success(String result) {
+                        wrapped.add(0, result);
+                        reply.reply(wrapped);
+                      }
 
-                        public void error(Throwable error) {
-                          ArrayList<Object> wrappedError = wrapError(error);
-                          reply.reply(wrappedError);
-                        }
-                      };
+                      public void error(Throwable error) {
+                        ArrayList<Object> wrappedError = wrapError(error);
+                        reply.reply(wrappedError);
+                      }
+                    };
 
-                  api.evaluateJavascript(
-                      (instanceIdArg == null) ? null : instanceIdArg.longValue(),
-                      javascriptStringArg,
-                      resultCallback);
-                } catch (Error | RuntimeException exception) {
-                  ArrayList<Object> wrappedError = wrapError(exception);
-                  reply.reply(wrappedError);
-                }
+                api.evaluateJavascript(
+                    (instanceIdArg == null) ? null : instanceIdArg.longValue(),
+                    javascriptStringArg,
+                    resultCallback);
               });
         } else {
           channel.setMessageHandler(null);
@@ -1191,17 +1122,13 @@
           channel.setMessageHandler(
               (message, reply) -> {
                 ArrayList<Object> wrapped = new ArrayList<Object>();
+                ArrayList<Object> args = (ArrayList<Object>) message;
+                Number instanceIdArg = (Number) args.get(0);
                 try {
-                  ArrayList<Object> args = (ArrayList<Object>) message;
-                  assert args != null;
-                  Number instanceIdArg = (Number) args.get(0);
-                  if (instanceIdArg == null) {
-                    throw new NullPointerException("instanceIdArg unexpectedly null.");
-                  }
                   String output =
                       api.getTitle((instanceIdArg == null) ? null : instanceIdArg.longValue());
                   wrapped.add(0, output);
-                } catch (Error | RuntimeException exception) {
+                } catch (Throwable exception) {
                   ArrayList<Object> wrappedError = wrapError(exception);
                   wrapped = wrappedError;
                 }
@@ -1219,27 +1146,17 @@
           channel.setMessageHandler(
               (message, reply) -> {
                 ArrayList<Object> wrapped = new ArrayList<Object>();
+                ArrayList<Object> args = (ArrayList<Object>) message;
+                Number instanceIdArg = (Number) args.get(0);
+                Number xArg = (Number) args.get(1);
+                Number yArg = (Number) args.get(2);
                 try {
-                  ArrayList<Object> args = (ArrayList<Object>) message;
-                  assert args != null;
-                  Number instanceIdArg = (Number) args.get(0);
-                  if (instanceIdArg == null) {
-                    throw new NullPointerException("instanceIdArg unexpectedly null.");
-                  }
-                  Number xArg = (Number) args.get(1);
-                  if (xArg == null) {
-                    throw new NullPointerException("xArg unexpectedly null.");
-                  }
-                  Number yArg = (Number) args.get(2);
-                  if (yArg == null) {
-                    throw new NullPointerException("yArg unexpectedly null.");
-                  }
                   api.scrollTo(
                       (instanceIdArg == null) ? null : instanceIdArg.longValue(),
                       (xArg == null) ? null : xArg.longValue(),
                       (yArg == null) ? null : yArg.longValue());
                   wrapped.add(0, null);
-                } catch (Error | RuntimeException exception) {
+                } catch (Throwable exception) {
                   ArrayList<Object> wrappedError = wrapError(exception);
                   wrapped = wrappedError;
                 }
@@ -1257,27 +1174,17 @@
           channel.setMessageHandler(
               (message, reply) -> {
                 ArrayList<Object> wrapped = new ArrayList<Object>();
+                ArrayList<Object> args = (ArrayList<Object>) message;
+                Number instanceIdArg = (Number) args.get(0);
+                Number xArg = (Number) args.get(1);
+                Number yArg = (Number) args.get(2);
                 try {
-                  ArrayList<Object> args = (ArrayList<Object>) message;
-                  assert args != null;
-                  Number instanceIdArg = (Number) args.get(0);
-                  if (instanceIdArg == null) {
-                    throw new NullPointerException("instanceIdArg unexpectedly null.");
-                  }
-                  Number xArg = (Number) args.get(1);
-                  if (xArg == null) {
-                    throw new NullPointerException("xArg unexpectedly null.");
-                  }
-                  Number yArg = (Number) args.get(2);
-                  if (yArg == null) {
-                    throw new NullPointerException("yArg unexpectedly null.");
-                  }
                   api.scrollBy(
                       (instanceIdArg == null) ? null : instanceIdArg.longValue(),
                       (xArg == null) ? null : xArg.longValue(),
                       (yArg == null) ? null : yArg.longValue());
                   wrapped.add(0, null);
-                } catch (Error | RuntimeException exception) {
+                } catch (Throwable exception) {
                   ArrayList<Object> wrappedError = wrapError(exception);
                   wrapped = wrappedError;
                 }
@@ -1295,17 +1202,13 @@
           channel.setMessageHandler(
               (message, reply) -> {
                 ArrayList<Object> wrapped = new ArrayList<Object>();
+                ArrayList<Object> args = (ArrayList<Object>) message;
+                Number instanceIdArg = (Number) args.get(0);
                 try {
-                  ArrayList<Object> args = (ArrayList<Object>) message;
-                  assert args != null;
-                  Number instanceIdArg = (Number) args.get(0);
-                  if (instanceIdArg == null) {
-                    throw new NullPointerException("instanceIdArg unexpectedly null.");
-                  }
                   Long output =
                       api.getScrollX((instanceIdArg == null) ? null : instanceIdArg.longValue());
                   wrapped.add(0, output);
-                } catch (Error | RuntimeException exception) {
+                } catch (Throwable exception) {
                   ArrayList<Object> wrappedError = wrapError(exception);
                   wrapped = wrappedError;
                 }
@@ -1323,17 +1226,13 @@
           channel.setMessageHandler(
               (message, reply) -> {
                 ArrayList<Object> wrapped = new ArrayList<Object>();
+                ArrayList<Object> args = (ArrayList<Object>) message;
+                Number instanceIdArg = (Number) args.get(0);
                 try {
-                  ArrayList<Object> args = (ArrayList<Object>) message;
-                  assert args != null;
-                  Number instanceIdArg = (Number) args.get(0);
-                  if (instanceIdArg == null) {
-                    throw new NullPointerException("instanceIdArg unexpectedly null.");
-                  }
                   Long output =
                       api.getScrollY((instanceIdArg == null) ? null : instanceIdArg.longValue());
                   wrapped.add(0, output);
-                } catch (Error | RuntimeException exception) {
+                } catch (Throwable exception) {
                   ArrayList<Object> wrappedError = wrapError(exception);
                   wrapped = wrappedError;
                 }
@@ -1351,18 +1250,14 @@
           channel.setMessageHandler(
               (message, reply) -> {
                 ArrayList<Object> wrapped = new ArrayList<Object>();
+                ArrayList<Object> args = (ArrayList<Object>) message;
+                Number instanceIdArg = (Number) args.get(0);
                 try {
-                  ArrayList<Object> args = (ArrayList<Object>) message;
-                  assert args != null;
-                  Number instanceIdArg = (Number) args.get(0);
-                  if (instanceIdArg == null) {
-                    throw new NullPointerException("instanceIdArg unexpectedly null.");
-                  }
                   WebViewPoint output =
                       api.getScrollPosition(
                           (instanceIdArg == null) ? null : instanceIdArg.longValue());
                   wrapped.add(0, output);
-                } catch (Error | RuntimeException exception) {
+                } catch (Throwable exception) {
                   ArrayList<Object> wrappedError = wrapError(exception);
                   wrapped = wrappedError;
                 }
@@ -1382,16 +1277,12 @@
           channel.setMessageHandler(
               (message, reply) -> {
                 ArrayList<Object> wrapped = new ArrayList<Object>();
+                ArrayList<Object> args = (ArrayList<Object>) message;
+                Boolean enabledArg = (Boolean) args.get(0);
                 try {
-                  ArrayList<Object> args = (ArrayList<Object>) message;
-                  assert args != null;
-                  Boolean enabledArg = (Boolean) args.get(0);
-                  if (enabledArg == null) {
-                    throw new NullPointerException("enabledArg unexpectedly null.");
-                  }
                   api.setWebContentsDebuggingEnabled(enabledArg);
                   wrapped.add(0, null);
-                } catch (Error | RuntimeException exception) {
+                } catch (Throwable exception) {
                   ArrayList<Object> wrappedError = wrapError(exception);
                   wrapped = wrappedError;
                 }
@@ -1409,24 +1300,17 @@
           channel.setMessageHandler(
               (message, reply) -> {
                 ArrayList<Object> wrapped = new ArrayList<Object>();
+                ArrayList<Object> args = (ArrayList<Object>) message;
+                Number instanceIdArg = (Number) args.get(0);
+                Number webViewClientInstanceIdArg = (Number) args.get(1);
                 try {
-                  ArrayList<Object> args = (ArrayList<Object>) message;
-                  assert args != null;
-                  Number instanceIdArg = (Number) args.get(0);
-                  if (instanceIdArg == null) {
-                    throw new NullPointerException("instanceIdArg unexpectedly null.");
-                  }
-                  Number webViewClientInstanceIdArg = (Number) args.get(1);
-                  if (webViewClientInstanceIdArg == null) {
-                    throw new NullPointerException("webViewClientInstanceIdArg unexpectedly null.");
-                  }
                   api.setWebViewClient(
                       (instanceIdArg == null) ? null : instanceIdArg.longValue(),
                       (webViewClientInstanceIdArg == null)
                           ? null
                           : webViewClientInstanceIdArg.longValue());
                   wrapped.add(0, null);
-                } catch (Error | RuntimeException exception) {
+                } catch (Throwable exception) {
                   ArrayList<Object> wrappedError = wrapError(exception);
                   wrapped = wrappedError;
                 }
@@ -1446,25 +1330,17 @@
           channel.setMessageHandler(
               (message, reply) -> {
                 ArrayList<Object> wrapped = new ArrayList<Object>();
+                ArrayList<Object> args = (ArrayList<Object>) message;
+                Number instanceIdArg = (Number) args.get(0);
+                Number javaScriptChannelInstanceIdArg = (Number) args.get(1);
                 try {
-                  ArrayList<Object> args = (ArrayList<Object>) message;
-                  assert args != null;
-                  Number instanceIdArg = (Number) args.get(0);
-                  if (instanceIdArg == null) {
-                    throw new NullPointerException("instanceIdArg unexpectedly null.");
-                  }
-                  Number javaScriptChannelInstanceIdArg = (Number) args.get(1);
-                  if (javaScriptChannelInstanceIdArg == null) {
-                    throw new NullPointerException(
-                        "javaScriptChannelInstanceIdArg unexpectedly null.");
-                  }
                   api.addJavaScriptChannel(
                       (instanceIdArg == null) ? null : instanceIdArg.longValue(),
                       (javaScriptChannelInstanceIdArg == null)
                           ? null
                           : javaScriptChannelInstanceIdArg.longValue());
                   wrapped.add(0, null);
-                } catch (Error | RuntimeException exception) {
+                } catch (Throwable exception) {
                   ArrayList<Object> wrappedError = wrapError(exception);
                   wrapped = wrappedError;
                 }
@@ -1484,25 +1360,17 @@
           channel.setMessageHandler(
               (message, reply) -> {
                 ArrayList<Object> wrapped = new ArrayList<Object>();
+                ArrayList<Object> args = (ArrayList<Object>) message;
+                Number instanceIdArg = (Number) args.get(0);
+                Number javaScriptChannelInstanceIdArg = (Number) args.get(1);
                 try {
-                  ArrayList<Object> args = (ArrayList<Object>) message;
-                  assert args != null;
-                  Number instanceIdArg = (Number) args.get(0);
-                  if (instanceIdArg == null) {
-                    throw new NullPointerException("instanceIdArg unexpectedly null.");
-                  }
-                  Number javaScriptChannelInstanceIdArg = (Number) args.get(1);
-                  if (javaScriptChannelInstanceIdArg == null) {
-                    throw new NullPointerException(
-                        "javaScriptChannelInstanceIdArg unexpectedly null.");
-                  }
                   api.removeJavaScriptChannel(
                       (instanceIdArg == null) ? null : instanceIdArg.longValue(),
                       (javaScriptChannelInstanceIdArg == null)
                           ? null
                           : javaScriptChannelInstanceIdArg.longValue());
                   wrapped.add(0, null);
-                } catch (Error | RuntimeException exception) {
+                } catch (Throwable exception) {
                   ArrayList<Object> wrappedError = wrapError(exception);
                   wrapped = wrappedError;
                 }
@@ -1522,19 +1390,15 @@
           channel.setMessageHandler(
               (message, reply) -> {
                 ArrayList<Object> wrapped = new ArrayList<Object>();
+                ArrayList<Object> args = (ArrayList<Object>) message;
+                Number instanceIdArg = (Number) args.get(0);
+                Number listenerInstanceIdArg = (Number) args.get(1);
                 try {
-                  ArrayList<Object> args = (ArrayList<Object>) message;
-                  assert args != null;
-                  Number instanceIdArg = (Number) args.get(0);
-                  if (instanceIdArg == null) {
-                    throw new NullPointerException("instanceIdArg unexpectedly null.");
-                  }
-                  Number listenerInstanceIdArg = (Number) args.get(1);
                   api.setDownloadListener(
                       (instanceIdArg == null) ? null : instanceIdArg.longValue(),
                       (listenerInstanceIdArg == null) ? null : listenerInstanceIdArg.longValue());
                   wrapped.add(0, null);
-                } catch (Error | RuntimeException exception) {
+                } catch (Throwable exception) {
                   ArrayList<Object> wrappedError = wrapError(exception);
                   wrapped = wrappedError;
                 }
@@ -1554,19 +1418,15 @@
           channel.setMessageHandler(
               (message, reply) -> {
                 ArrayList<Object> wrapped = new ArrayList<Object>();
+                ArrayList<Object> args = (ArrayList<Object>) message;
+                Number instanceIdArg = (Number) args.get(0);
+                Number clientInstanceIdArg = (Number) args.get(1);
                 try {
-                  ArrayList<Object> args = (ArrayList<Object>) message;
-                  assert args != null;
-                  Number instanceIdArg = (Number) args.get(0);
-                  if (instanceIdArg == null) {
-                    throw new NullPointerException("instanceIdArg unexpectedly null.");
-                  }
-                  Number clientInstanceIdArg = (Number) args.get(1);
                   api.setWebChromeClient(
                       (instanceIdArg == null) ? null : instanceIdArg.longValue(),
                       (clientInstanceIdArg == null) ? null : clientInstanceIdArg.longValue());
                   wrapped.add(0, null);
-                } catch (Error | RuntimeException exception) {
+                } catch (Throwable exception) {
                   ArrayList<Object> wrappedError = wrapError(exception);
                   wrapped = wrappedError;
                 }
@@ -1586,22 +1446,15 @@
           channel.setMessageHandler(
               (message, reply) -> {
                 ArrayList<Object> wrapped = new ArrayList<Object>();
+                ArrayList<Object> args = (ArrayList<Object>) message;
+                Number instanceIdArg = (Number) args.get(0);
+                Number colorArg = (Number) args.get(1);
                 try {
-                  ArrayList<Object> args = (ArrayList<Object>) message;
-                  assert args != null;
-                  Number instanceIdArg = (Number) args.get(0);
-                  if (instanceIdArg == null) {
-                    throw new NullPointerException("instanceIdArg unexpectedly null.");
-                  }
-                  Number colorArg = (Number) args.get(1);
-                  if (colorArg == null) {
-                    throw new NullPointerException("colorArg unexpectedly null.");
-                  }
                   api.setBackgroundColor(
                       (instanceIdArg == null) ? null : instanceIdArg.longValue(),
                       (colorArg == null) ? null : colorArg.longValue());
                   wrapped.add(0, null);
-                } catch (Error | RuntimeException exception) {
+                } catch (Throwable exception) {
                   ArrayList<Object> wrappedError = wrapError(exception);
                   wrapped = wrappedError;
                 }
@@ -1624,22 +1477,23 @@
    * <p>Generated class from Pigeon that represents Flutter messages that can be called from Java.
    */
   public static class WebViewFlutterApi {
-    private final BinaryMessenger binaryMessenger;
+    private final @NonNull BinaryMessenger binaryMessenger;
 
-    public WebViewFlutterApi(BinaryMessenger argBinaryMessenger) {
+    public WebViewFlutterApi(@NonNull BinaryMessenger argBinaryMessenger) {
       this.binaryMessenger = argBinaryMessenger;
     }
 
     /** Public interface for sending reply. */
+    @SuppressWarnings("UnknownNullness")
     public interface Reply<T> {
       void reply(T reply);
     }
     /** The codec used by WebViewFlutterApi. */
-    static MessageCodec<Object> getCodec() {
+    static @NonNull MessageCodec<Object> getCodec() {
       return new StandardMessageCodec();
     }
     /** Create a new Dart instance and add it to the `InstanceManager`. */
-    public void create(@NonNull Long identifierArg, Reply<Void> callback) {
+    public void create(@NonNull Long identifierArg, @NonNull Reply<Void> callback) {
       BasicMessageChannel<Object> channel =
           new BasicMessageChannel<>(
               binaryMessenger, "dev.flutter.pigeon.WebViewFlutterApi.create", getCodec());
@@ -1680,13 +1534,13 @@
     void setTextZoom(@NonNull Long instanceId, @NonNull Long textZoom);
 
     /** The codec used by WebSettingsHostApi. */
-    static MessageCodec<Object> getCodec() {
+    static @NonNull MessageCodec<Object> getCodec() {
       return new StandardMessageCodec();
     }
     /**
      * Sets up an instance of `WebSettingsHostApi` to handle messages through the `binaryMessenger`.
      */
-    static void setup(BinaryMessenger binaryMessenger, WebSettingsHostApi api) {
+    static void setup(@NonNull BinaryMessenger binaryMessenger, @Nullable WebSettingsHostApi api) {
       {
         BasicMessageChannel<Object> channel =
             new BasicMessageChannel<>(
@@ -1695,22 +1549,15 @@
           channel.setMessageHandler(
               (message, reply) -> {
                 ArrayList<Object> wrapped = new ArrayList<Object>();
+                ArrayList<Object> args = (ArrayList<Object>) message;
+                Number instanceIdArg = (Number) args.get(0);
+                Number webViewInstanceIdArg = (Number) args.get(1);
                 try {
-                  ArrayList<Object> args = (ArrayList<Object>) message;
-                  assert args != null;
-                  Number instanceIdArg = (Number) args.get(0);
-                  if (instanceIdArg == null) {
-                    throw new NullPointerException("instanceIdArg unexpectedly null.");
-                  }
-                  Number webViewInstanceIdArg = (Number) args.get(1);
-                  if (webViewInstanceIdArg == null) {
-                    throw new NullPointerException("webViewInstanceIdArg unexpectedly null.");
-                  }
                   api.create(
                       (instanceIdArg == null) ? null : instanceIdArg.longValue(),
                       (webViewInstanceIdArg == null) ? null : webViewInstanceIdArg.longValue());
                   wrapped.add(0, null);
-                } catch (Error | RuntimeException exception) {
+                } catch (Throwable exception) {
                   ArrayList<Object> wrappedError = wrapError(exception);
                   wrapped = wrappedError;
                 }
@@ -1730,21 +1577,14 @@
           channel.setMessageHandler(
               (message, reply) -> {
                 ArrayList<Object> wrapped = new ArrayList<Object>();
+                ArrayList<Object> args = (ArrayList<Object>) message;
+                Number instanceIdArg = (Number) args.get(0);
+                Boolean flagArg = (Boolean) args.get(1);
                 try {
-                  ArrayList<Object> args = (ArrayList<Object>) message;
-                  assert args != null;
-                  Number instanceIdArg = (Number) args.get(0);
-                  if (instanceIdArg == null) {
-                    throw new NullPointerException("instanceIdArg unexpectedly null.");
-                  }
-                  Boolean flagArg = (Boolean) args.get(1);
-                  if (flagArg == null) {
-                    throw new NullPointerException("flagArg unexpectedly null.");
-                  }
                   api.setDomStorageEnabled(
                       (instanceIdArg == null) ? null : instanceIdArg.longValue(), flagArg);
                   wrapped.add(0, null);
-                } catch (Error | RuntimeException exception) {
+                } catch (Throwable exception) {
                   ArrayList<Object> wrappedError = wrapError(exception);
                   wrapped = wrappedError;
                 }
@@ -1764,21 +1604,14 @@
           channel.setMessageHandler(
               (message, reply) -> {
                 ArrayList<Object> wrapped = new ArrayList<Object>();
+                ArrayList<Object> args = (ArrayList<Object>) message;
+                Number instanceIdArg = (Number) args.get(0);
+                Boolean flagArg = (Boolean) args.get(1);
                 try {
-                  ArrayList<Object> args = (ArrayList<Object>) message;
-                  assert args != null;
-                  Number instanceIdArg = (Number) args.get(0);
-                  if (instanceIdArg == null) {
-                    throw new NullPointerException("instanceIdArg unexpectedly null.");
-                  }
-                  Boolean flagArg = (Boolean) args.get(1);
-                  if (flagArg == null) {
-                    throw new NullPointerException("flagArg unexpectedly null.");
-                  }
                   api.setJavaScriptCanOpenWindowsAutomatically(
                       (instanceIdArg == null) ? null : instanceIdArg.longValue(), flagArg);
                   wrapped.add(0, null);
-                } catch (Error | RuntimeException exception) {
+                } catch (Throwable exception) {
                   ArrayList<Object> wrappedError = wrapError(exception);
                   wrapped = wrappedError;
                 }
@@ -1798,21 +1631,14 @@
           channel.setMessageHandler(
               (message, reply) -> {
                 ArrayList<Object> wrapped = new ArrayList<Object>();
+                ArrayList<Object> args = (ArrayList<Object>) message;
+                Number instanceIdArg = (Number) args.get(0);
+                Boolean supportArg = (Boolean) args.get(1);
                 try {
-                  ArrayList<Object> args = (ArrayList<Object>) message;
-                  assert args != null;
-                  Number instanceIdArg = (Number) args.get(0);
-                  if (instanceIdArg == null) {
-                    throw new NullPointerException("instanceIdArg unexpectedly null.");
-                  }
-                  Boolean supportArg = (Boolean) args.get(1);
-                  if (supportArg == null) {
-                    throw new NullPointerException("supportArg unexpectedly null.");
-                  }
                   api.setSupportMultipleWindows(
                       (instanceIdArg == null) ? null : instanceIdArg.longValue(), supportArg);
                   wrapped.add(0, null);
-                } catch (Error | RuntimeException exception) {
+                } catch (Throwable exception) {
                   ArrayList<Object> wrappedError = wrapError(exception);
                   wrapped = wrappedError;
                 }
@@ -1832,21 +1658,14 @@
           channel.setMessageHandler(
               (message, reply) -> {
                 ArrayList<Object> wrapped = new ArrayList<Object>();
+                ArrayList<Object> args = (ArrayList<Object>) message;
+                Number instanceIdArg = (Number) args.get(0);
+                Boolean flagArg = (Boolean) args.get(1);
                 try {
-                  ArrayList<Object> args = (ArrayList<Object>) message;
-                  assert args != null;
-                  Number instanceIdArg = (Number) args.get(0);
-                  if (instanceIdArg == null) {
-                    throw new NullPointerException("instanceIdArg unexpectedly null.");
-                  }
-                  Boolean flagArg = (Boolean) args.get(1);
-                  if (flagArg == null) {
-                    throw new NullPointerException("flagArg unexpectedly null.");
-                  }
                   api.setJavaScriptEnabled(
                       (instanceIdArg == null) ? null : instanceIdArg.longValue(), flagArg);
                   wrapped.add(0, null);
-                } catch (Error | RuntimeException exception) {
+                } catch (Throwable exception) {
                   ArrayList<Object> wrappedError = wrapError(exception);
                   wrapped = wrappedError;
                 }
@@ -1866,19 +1685,15 @@
           channel.setMessageHandler(
               (message, reply) -> {
                 ArrayList<Object> wrapped = new ArrayList<Object>();
+                ArrayList<Object> args = (ArrayList<Object>) message;
+                Number instanceIdArg = (Number) args.get(0);
+                String userAgentStringArg = (String) args.get(1);
                 try {
-                  ArrayList<Object> args = (ArrayList<Object>) message;
-                  assert args != null;
-                  Number instanceIdArg = (Number) args.get(0);
-                  if (instanceIdArg == null) {
-                    throw new NullPointerException("instanceIdArg unexpectedly null.");
-                  }
-                  String userAgentStringArg = (String) args.get(1);
                   api.setUserAgentString(
                       (instanceIdArg == null) ? null : instanceIdArg.longValue(),
                       userAgentStringArg);
                   wrapped.add(0, null);
-                } catch (Error | RuntimeException exception) {
+                } catch (Throwable exception) {
                   ArrayList<Object> wrappedError = wrapError(exception);
                   wrapped = wrappedError;
                 }
@@ -1898,21 +1713,14 @@
           channel.setMessageHandler(
               (message, reply) -> {
                 ArrayList<Object> wrapped = new ArrayList<Object>();
+                ArrayList<Object> args = (ArrayList<Object>) message;
+                Number instanceIdArg = (Number) args.get(0);
+                Boolean requireArg = (Boolean) args.get(1);
                 try {
-                  ArrayList<Object> args = (ArrayList<Object>) message;
-                  assert args != null;
-                  Number instanceIdArg = (Number) args.get(0);
-                  if (instanceIdArg == null) {
-                    throw new NullPointerException("instanceIdArg unexpectedly null.");
-                  }
-                  Boolean requireArg = (Boolean) args.get(1);
-                  if (requireArg == null) {
-                    throw new NullPointerException("requireArg unexpectedly null.");
-                  }
                   api.setMediaPlaybackRequiresUserGesture(
                       (instanceIdArg == null) ? null : instanceIdArg.longValue(), requireArg);
                   wrapped.add(0, null);
-                } catch (Error | RuntimeException exception) {
+                } catch (Throwable exception) {
                   ArrayList<Object> wrappedError = wrapError(exception);
                   wrapped = wrappedError;
                 }
@@ -1932,21 +1740,14 @@
           channel.setMessageHandler(
               (message, reply) -> {
                 ArrayList<Object> wrapped = new ArrayList<Object>();
+                ArrayList<Object> args = (ArrayList<Object>) message;
+                Number instanceIdArg = (Number) args.get(0);
+                Boolean supportArg = (Boolean) args.get(1);
                 try {
-                  ArrayList<Object> args = (ArrayList<Object>) message;
-                  assert args != null;
-                  Number instanceIdArg = (Number) args.get(0);
-                  if (instanceIdArg == null) {
-                    throw new NullPointerException("instanceIdArg unexpectedly null.");
-                  }
-                  Boolean supportArg = (Boolean) args.get(1);
-                  if (supportArg == null) {
-                    throw new NullPointerException("supportArg unexpectedly null.");
-                  }
                   api.setSupportZoom(
                       (instanceIdArg == null) ? null : instanceIdArg.longValue(), supportArg);
                   wrapped.add(0, null);
-                } catch (Error | RuntimeException exception) {
+                } catch (Throwable exception) {
                   ArrayList<Object> wrappedError = wrapError(exception);
                   wrapped = wrappedError;
                 }
@@ -1966,21 +1767,14 @@
           channel.setMessageHandler(
               (message, reply) -> {
                 ArrayList<Object> wrapped = new ArrayList<Object>();
+                ArrayList<Object> args = (ArrayList<Object>) message;
+                Number instanceIdArg = (Number) args.get(0);
+                Boolean overviewArg = (Boolean) args.get(1);
                 try {
-                  ArrayList<Object> args = (ArrayList<Object>) message;
-                  assert args != null;
-                  Number instanceIdArg = (Number) args.get(0);
-                  if (instanceIdArg == null) {
-                    throw new NullPointerException("instanceIdArg unexpectedly null.");
-                  }
-                  Boolean overviewArg = (Boolean) args.get(1);
-                  if (overviewArg == null) {
-                    throw new NullPointerException("overviewArg unexpectedly null.");
-                  }
                   api.setLoadWithOverviewMode(
                       (instanceIdArg == null) ? null : instanceIdArg.longValue(), overviewArg);
                   wrapped.add(0, null);
-                } catch (Error | RuntimeException exception) {
+                } catch (Throwable exception) {
                   ArrayList<Object> wrappedError = wrapError(exception);
                   wrapped = wrappedError;
                 }
@@ -2000,21 +1794,14 @@
           channel.setMessageHandler(
               (message, reply) -> {
                 ArrayList<Object> wrapped = new ArrayList<Object>();
+                ArrayList<Object> args = (ArrayList<Object>) message;
+                Number instanceIdArg = (Number) args.get(0);
+                Boolean useArg = (Boolean) args.get(1);
                 try {
-                  ArrayList<Object> args = (ArrayList<Object>) message;
-                  assert args != null;
-                  Number instanceIdArg = (Number) args.get(0);
-                  if (instanceIdArg == null) {
-                    throw new NullPointerException("instanceIdArg unexpectedly null.");
-                  }
-                  Boolean useArg = (Boolean) args.get(1);
-                  if (useArg == null) {
-                    throw new NullPointerException("useArg unexpectedly null.");
-                  }
                   api.setUseWideViewPort(
                       (instanceIdArg == null) ? null : instanceIdArg.longValue(), useArg);
                   wrapped.add(0, null);
-                } catch (Error | RuntimeException exception) {
+                } catch (Throwable exception) {
                   ArrayList<Object> wrappedError = wrapError(exception);
                   wrapped = wrappedError;
                 }
@@ -2034,21 +1821,14 @@
           channel.setMessageHandler(
               (message, reply) -> {
                 ArrayList<Object> wrapped = new ArrayList<Object>();
+                ArrayList<Object> args = (ArrayList<Object>) message;
+                Number instanceIdArg = (Number) args.get(0);
+                Boolean enabledArg = (Boolean) args.get(1);
                 try {
-                  ArrayList<Object> args = (ArrayList<Object>) message;
-                  assert args != null;
-                  Number instanceIdArg = (Number) args.get(0);
-                  if (instanceIdArg == null) {
-                    throw new NullPointerException("instanceIdArg unexpectedly null.");
-                  }
-                  Boolean enabledArg = (Boolean) args.get(1);
-                  if (enabledArg == null) {
-                    throw new NullPointerException("enabledArg unexpectedly null.");
-                  }
                   api.setDisplayZoomControls(
                       (instanceIdArg == null) ? null : instanceIdArg.longValue(), enabledArg);
                   wrapped.add(0, null);
-                } catch (Error | RuntimeException exception) {
+                } catch (Throwable exception) {
                   ArrayList<Object> wrappedError = wrapError(exception);
                   wrapped = wrappedError;
                 }
@@ -2068,21 +1848,14 @@
           channel.setMessageHandler(
               (message, reply) -> {
                 ArrayList<Object> wrapped = new ArrayList<Object>();
+                ArrayList<Object> args = (ArrayList<Object>) message;
+                Number instanceIdArg = (Number) args.get(0);
+                Boolean enabledArg = (Boolean) args.get(1);
                 try {
-                  ArrayList<Object> args = (ArrayList<Object>) message;
-                  assert args != null;
-                  Number instanceIdArg = (Number) args.get(0);
-                  if (instanceIdArg == null) {
-                    throw new NullPointerException("instanceIdArg unexpectedly null.");
-                  }
-                  Boolean enabledArg = (Boolean) args.get(1);
-                  if (enabledArg == null) {
-                    throw new NullPointerException("enabledArg unexpectedly null.");
-                  }
                   api.setBuiltInZoomControls(
                       (instanceIdArg == null) ? null : instanceIdArg.longValue(), enabledArg);
                   wrapped.add(0, null);
-                } catch (Error | RuntimeException exception) {
+                } catch (Throwable exception) {
                   ArrayList<Object> wrappedError = wrapError(exception);
                   wrapped = wrappedError;
                 }
@@ -2102,21 +1875,14 @@
           channel.setMessageHandler(
               (message, reply) -> {
                 ArrayList<Object> wrapped = new ArrayList<Object>();
+                ArrayList<Object> args = (ArrayList<Object>) message;
+                Number instanceIdArg = (Number) args.get(0);
+                Boolean enabledArg = (Boolean) args.get(1);
                 try {
-                  ArrayList<Object> args = (ArrayList<Object>) message;
-                  assert args != null;
-                  Number instanceIdArg = (Number) args.get(0);
-                  if (instanceIdArg == null) {
-                    throw new NullPointerException("instanceIdArg unexpectedly null.");
-                  }
-                  Boolean enabledArg = (Boolean) args.get(1);
-                  if (enabledArg == null) {
-                    throw new NullPointerException("enabledArg unexpectedly null.");
-                  }
                   api.setAllowFileAccess(
                       (instanceIdArg == null) ? null : instanceIdArg.longValue(), enabledArg);
                   wrapped.add(0, null);
-                } catch (Error | RuntimeException exception) {
+                } catch (Throwable exception) {
                   ArrayList<Object> wrappedError = wrapError(exception);
                   wrapped = wrappedError;
                 }
@@ -2134,22 +1900,15 @@
           channel.setMessageHandler(
               (message, reply) -> {
                 ArrayList<Object> wrapped = new ArrayList<Object>();
+                ArrayList<Object> args = (ArrayList<Object>) message;
+                Number instanceIdArg = (Number) args.get(0);
+                Number textZoomArg = (Number) args.get(1);
                 try {
-                  ArrayList<Object> args = (ArrayList<Object>) message;
-                  assert args != null;
-                  Number instanceIdArg = (Number) args.get(0);
-                  if (instanceIdArg == null) {
-                    throw new NullPointerException("instanceIdArg unexpectedly null.");
-                  }
-                  Number textZoomArg = (Number) args.get(1);
-                  if (textZoomArg == null) {
-                    throw new NullPointerException("textZoomArg unexpectedly null.");
-                  }
                   api.setTextZoom(
                       (instanceIdArg == null) ? null : instanceIdArg.longValue(),
                       (textZoomArg == null) ? null : textZoomArg.longValue());
                   wrapped.add(0, null);
-                } catch (Error | RuntimeException exception) {
+                } catch (Throwable exception) {
                   ArrayList<Object> wrappedError = wrapError(exception);
                   wrapped = wrappedError;
                 }
@@ -2167,14 +1926,15 @@
     void create(@NonNull Long instanceId, @NonNull String channelName);
 
     /** The codec used by JavaScriptChannelHostApi. */
-    static MessageCodec<Object> getCodec() {
+    static @NonNull MessageCodec<Object> getCodec() {
       return new StandardMessageCodec();
     }
     /**
      * Sets up an instance of `JavaScriptChannelHostApi` to handle messages through the
      * `binaryMessenger`.
      */
-    static void setup(BinaryMessenger binaryMessenger, JavaScriptChannelHostApi api) {
+    static void setup(
+        @NonNull BinaryMessenger binaryMessenger, @Nullable JavaScriptChannelHostApi api) {
       {
         BasicMessageChannel<Object> channel =
             new BasicMessageChannel<>(
@@ -2183,21 +1943,14 @@
           channel.setMessageHandler(
               (message, reply) -> {
                 ArrayList<Object> wrapped = new ArrayList<Object>();
+                ArrayList<Object> args = (ArrayList<Object>) message;
+                Number instanceIdArg = (Number) args.get(0);
+                String channelNameArg = (String) args.get(1);
                 try {
-                  ArrayList<Object> args = (ArrayList<Object>) message;
-                  assert args != null;
-                  Number instanceIdArg = (Number) args.get(0);
-                  if (instanceIdArg == null) {
-                    throw new NullPointerException("instanceIdArg unexpectedly null.");
-                  }
-                  String channelNameArg = (String) args.get(1);
-                  if (channelNameArg == null) {
-                    throw new NullPointerException("channelNameArg unexpectedly null.");
-                  }
                   api.create(
                       (instanceIdArg == null) ? null : instanceIdArg.longValue(), channelNameArg);
                   wrapped.add(0, null);
-                } catch (Error | RuntimeException exception) {
+                } catch (Throwable exception) {
                   ArrayList<Object> wrappedError = wrapError(exception);
                   wrapped = wrappedError;
                 }
@@ -2211,23 +1964,24 @@
   }
   /** Generated class from Pigeon that represents Flutter messages that can be called from Java. */
   public static class JavaScriptChannelFlutterApi {
-    private final BinaryMessenger binaryMessenger;
+    private final @NonNull BinaryMessenger binaryMessenger;
 
-    public JavaScriptChannelFlutterApi(BinaryMessenger argBinaryMessenger) {
+    public JavaScriptChannelFlutterApi(@NonNull BinaryMessenger argBinaryMessenger) {
       this.binaryMessenger = argBinaryMessenger;
     }
 
     /** Public interface for sending reply. */
+    @SuppressWarnings("UnknownNullness")
     public interface Reply<T> {
       void reply(T reply);
     }
     /** The codec used by JavaScriptChannelFlutterApi. */
-    static MessageCodec<Object> getCodec() {
+    static @NonNull MessageCodec<Object> getCodec() {
       return new StandardMessageCodec();
     }
 
     public void postMessage(
-        @NonNull Long instanceIdArg, @NonNull String messageArg, Reply<Void> callback) {
+        @NonNull Long instanceIdArg, @NonNull String messageArg, @NonNull Reply<Void> callback) {
       BasicMessageChannel<Object> channel =
           new BasicMessageChannel<>(
               binaryMessenger,
@@ -2247,14 +2001,15 @@
         @NonNull Long instanceId, @NonNull Boolean value);
 
     /** The codec used by WebViewClientHostApi. */
-    static MessageCodec<Object> getCodec() {
+    static @NonNull MessageCodec<Object> getCodec() {
       return new StandardMessageCodec();
     }
     /**
      * Sets up an instance of `WebViewClientHostApi` to handle messages through the
      * `binaryMessenger`.
      */
-    static void setup(BinaryMessenger binaryMessenger, WebViewClientHostApi api) {
+    static void setup(
+        @NonNull BinaryMessenger binaryMessenger, @Nullable WebViewClientHostApi api) {
       {
         BasicMessageChannel<Object> channel =
             new BasicMessageChannel<>(
@@ -2263,16 +2018,12 @@
           channel.setMessageHandler(
               (message, reply) -> {
                 ArrayList<Object> wrapped = new ArrayList<Object>();
+                ArrayList<Object> args = (ArrayList<Object>) message;
+                Number instanceIdArg = (Number) args.get(0);
                 try {
-                  ArrayList<Object> args = (ArrayList<Object>) message;
-                  assert args != null;
-                  Number instanceIdArg = (Number) args.get(0);
-                  if (instanceIdArg == null) {
-                    throw new NullPointerException("instanceIdArg unexpectedly null.");
-                  }
                   api.create((instanceIdArg == null) ? null : instanceIdArg.longValue());
                   wrapped.add(0, null);
-                } catch (Error | RuntimeException exception) {
+                } catch (Throwable exception) {
                   ArrayList<Object> wrappedError = wrapError(exception);
                   wrapped = wrappedError;
                 }
@@ -2292,21 +2043,14 @@
           channel.setMessageHandler(
               (message, reply) -> {
                 ArrayList<Object> wrapped = new ArrayList<Object>();
+                ArrayList<Object> args = (ArrayList<Object>) message;
+                Number instanceIdArg = (Number) args.get(0);
+                Boolean valueArg = (Boolean) args.get(1);
                 try {
-                  ArrayList<Object> args = (ArrayList<Object>) message;
-                  assert args != null;
-                  Number instanceIdArg = (Number) args.get(0);
-                  if (instanceIdArg == null) {
-                    throw new NullPointerException("instanceIdArg unexpectedly null.");
-                  }
-                  Boolean valueArg = (Boolean) args.get(1);
-                  if (valueArg == null) {
-                    throw new NullPointerException("valueArg unexpectedly null.");
-                  }
                   api.setSynchronousReturnValueForShouldOverrideUrlLoading(
                       (instanceIdArg == null) ? null : instanceIdArg.longValue(), valueArg);
                   wrapped.add(0, null);
-                } catch (Error | RuntimeException exception) {
+                } catch (Throwable exception) {
                   ArrayList<Object> wrappedError = wrapError(exception);
                   wrapped = wrappedError;
                 }
@@ -2352,18 +2096,19 @@
 
   /** Generated class from Pigeon that represents Flutter messages that can be called from Java. */
   public static class WebViewClientFlutterApi {
-    private final BinaryMessenger binaryMessenger;
+    private final @NonNull BinaryMessenger binaryMessenger;
 
-    public WebViewClientFlutterApi(BinaryMessenger argBinaryMessenger) {
+    public WebViewClientFlutterApi(@NonNull BinaryMessenger argBinaryMessenger) {
       this.binaryMessenger = argBinaryMessenger;
     }
 
     /** Public interface for sending reply. */
+    @SuppressWarnings("UnknownNullness")
     public interface Reply<T> {
       void reply(T reply);
     }
     /** The codec used by WebViewClientFlutterApi. */
-    static MessageCodec<Object> getCodec() {
+    static @NonNull MessageCodec<Object> getCodec() {
       return WebViewClientFlutterApiCodec.INSTANCE;
     }
 
@@ -2371,7 +2116,7 @@
         @NonNull Long instanceIdArg,
         @NonNull Long webViewInstanceIdArg,
         @NonNull String urlArg,
-        Reply<Void> callback) {
+        @NonNull Reply<Void> callback) {
       BasicMessageChannel<Object> channel =
           new BasicMessageChannel<>(
               binaryMessenger,
@@ -2386,7 +2131,7 @@
         @NonNull Long instanceIdArg,
         @NonNull Long webViewInstanceIdArg,
         @NonNull String urlArg,
-        Reply<Void> callback) {
+        @NonNull Reply<Void> callback) {
       BasicMessageChannel<Object> channel =
           new BasicMessageChannel<>(
               binaryMessenger,
@@ -2402,7 +2147,7 @@
         @NonNull Long webViewInstanceIdArg,
         @NonNull WebResourceRequestData requestArg,
         @NonNull WebResourceErrorData errorArg,
-        Reply<Void> callback) {
+        @NonNull Reply<Void> callback) {
       BasicMessageChannel<Object> channel =
           new BasicMessageChannel<>(
               binaryMessenger,
@@ -2420,7 +2165,7 @@
         @NonNull Long errorCodeArg,
         @NonNull String descriptionArg,
         @NonNull String failingUrlArg,
-        Reply<Void> callback) {
+        @NonNull Reply<Void> callback) {
       BasicMessageChannel<Object> channel =
           new BasicMessageChannel<>(
               binaryMessenger,
@@ -2441,7 +2186,7 @@
         @NonNull Long instanceIdArg,
         @NonNull Long webViewInstanceIdArg,
         @NonNull WebResourceRequestData requestArg,
-        Reply<Void> callback) {
+        @NonNull Reply<Void> callback) {
       BasicMessageChannel<Object> channel =
           new BasicMessageChannel<>(
               binaryMessenger,
@@ -2456,7 +2201,7 @@
         @NonNull Long instanceIdArg,
         @NonNull Long webViewInstanceIdArg,
         @NonNull String urlArg,
-        Reply<Void> callback) {
+        @NonNull Reply<Void> callback) {
       BasicMessageChannel<Object> channel =
           new BasicMessageChannel<>(
               binaryMessenger, "dev.flutter.pigeon.WebViewClientFlutterApi.urlLoading", getCodec());
@@ -2464,6 +2209,23 @@
           new ArrayList<Object>(Arrays.asList(instanceIdArg, webViewInstanceIdArg, urlArg)),
           channelReply -> callback.reply(null));
     }
+
+    public void doUpdateVisitedHistory(
+        @NonNull Long instanceIdArg,
+        @NonNull Long webViewInstanceIdArg,
+        @NonNull String urlArg,
+        @NonNull Boolean isReloadArg,
+        @NonNull Reply<Void> callback) {
+      BasicMessageChannel<Object> channel =
+          new BasicMessageChannel<>(
+              binaryMessenger,
+              "dev.flutter.pigeon.WebViewClientFlutterApi.doUpdateVisitedHistory",
+              getCodec());
+      channel.send(
+          new ArrayList<Object>(
+              Arrays.asList(instanceIdArg, webViewInstanceIdArg, urlArg, isReloadArg)),
+          channelReply -> callback.reply(null));
+    }
   }
   /** Generated interface from Pigeon that represents a handler of messages from Flutter. */
   public interface DownloadListenerHostApi {
@@ -2471,14 +2233,15 @@
     void create(@NonNull Long instanceId);
 
     /** The codec used by DownloadListenerHostApi. */
-    static MessageCodec<Object> getCodec() {
+    static @NonNull MessageCodec<Object> getCodec() {
       return new StandardMessageCodec();
     }
     /**
      * Sets up an instance of `DownloadListenerHostApi` to handle messages through the
      * `binaryMessenger`.
      */
-    static void setup(BinaryMessenger binaryMessenger, DownloadListenerHostApi api) {
+    static void setup(
+        @NonNull BinaryMessenger binaryMessenger, @Nullable DownloadListenerHostApi api) {
       {
         BasicMessageChannel<Object> channel =
             new BasicMessageChannel<>(
@@ -2487,16 +2250,12 @@
           channel.setMessageHandler(
               (message, reply) -> {
                 ArrayList<Object> wrapped = new ArrayList<Object>();
+                ArrayList<Object> args = (ArrayList<Object>) message;
+                Number instanceIdArg = (Number) args.get(0);
                 try {
-                  ArrayList<Object> args = (ArrayList<Object>) message;
-                  assert args != null;
-                  Number instanceIdArg = (Number) args.get(0);
-                  if (instanceIdArg == null) {
-                    throw new NullPointerException("instanceIdArg unexpectedly null.");
-                  }
                   api.create((instanceIdArg == null) ? null : instanceIdArg.longValue());
                   wrapped.add(0, null);
-                } catch (Error | RuntimeException exception) {
+                } catch (Throwable exception) {
                   ArrayList<Object> wrappedError = wrapError(exception);
                   wrapped = wrappedError;
                 }
@@ -2510,18 +2269,19 @@
   }
   /** Generated class from Pigeon that represents Flutter messages that can be called from Java. */
   public static class DownloadListenerFlutterApi {
-    private final BinaryMessenger binaryMessenger;
+    private final @NonNull BinaryMessenger binaryMessenger;
 
-    public DownloadListenerFlutterApi(BinaryMessenger argBinaryMessenger) {
+    public DownloadListenerFlutterApi(@NonNull BinaryMessenger argBinaryMessenger) {
       this.binaryMessenger = argBinaryMessenger;
     }
 
     /** Public interface for sending reply. */
+    @SuppressWarnings("UnknownNullness")
     public interface Reply<T> {
       void reply(T reply);
     }
     /** The codec used by DownloadListenerFlutterApi. */
-    static MessageCodec<Object> getCodec() {
+    static @NonNull MessageCodec<Object> getCodec() {
       return new StandardMessageCodec();
     }
 
@@ -2532,7 +2292,7 @@
         @NonNull String contentDispositionArg,
         @NonNull String mimetypeArg,
         @NonNull Long contentLengthArg,
-        Reply<Void> callback) {
+        @NonNull Reply<Void> callback) {
       BasicMessageChannel<Object> channel =
           new BasicMessageChannel<>(
               binaryMessenger,
@@ -2559,14 +2319,15 @@
         @NonNull Long instanceId, @NonNull Boolean value);
 
     /** The codec used by WebChromeClientHostApi. */
-    static MessageCodec<Object> getCodec() {
+    static @NonNull MessageCodec<Object> getCodec() {
       return new StandardMessageCodec();
     }
     /**
      * Sets up an instance of `WebChromeClientHostApi` to handle messages through the
      * `binaryMessenger`.
      */
-    static void setup(BinaryMessenger binaryMessenger, WebChromeClientHostApi api) {
+    static void setup(
+        @NonNull BinaryMessenger binaryMessenger, @Nullable WebChromeClientHostApi api) {
       {
         BasicMessageChannel<Object> channel =
             new BasicMessageChannel<>(
@@ -2575,16 +2336,12 @@
           channel.setMessageHandler(
               (message, reply) -> {
                 ArrayList<Object> wrapped = new ArrayList<Object>();
+                ArrayList<Object> args = (ArrayList<Object>) message;
+                Number instanceIdArg = (Number) args.get(0);
                 try {
-                  ArrayList<Object> args = (ArrayList<Object>) message;
-                  assert args != null;
-                  Number instanceIdArg = (Number) args.get(0);
-                  if (instanceIdArg == null) {
-                    throw new NullPointerException("instanceIdArg unexpectedly null.");
-                  }
                   api.create((instanceIdArg == null) ? null : instanceIdArg.longValue());
                   wrapped.add(0, null);
-                } catch (Error | RuntimeException exception) {
+                } catch (Throwable exception) {
                   ArrayList<Object> wrappedError = wrapError(exception);
                   wrapped = wrappedError;
                 }
@@ -2604,21 +2361,14 @@
           channel.setMessageHandler(
               (message, reply) -> {
                 ArrayList<Object> wrapped = new ArrayList<Object>();
+                ArrayList<Object> args = (ArrayList<Object>) message;
+                Number instanceIdArg = (Number) args.get(0);
+                Boolean valueArg = (Boolean) args.get(1);
                 try {
-                  ArrayList<Object> args = (ArrayList<Object>) message;
-                  assert args != null;
-                  Number instanceIdArg = (Number) args.get(0);
-                  if (instanceIdArg == null) {
-                    throw new NullPointerException("instanceIdArg unexpectedly null.");
-                  }
-                  Boolean valueArg = (Boolean) args.get(1);
-                  if (valueArg == null) {
-                    throw new NullPointerException("valueArg unexpectedly null.");
-                  }
                   api.setSynchronousReturnValueForOnShowFileChooser(
                       (instanceIdArg == null) ? null : instanceIdArg.longValue(), valueArg);
                   wrapped.add(0, null);
-                } catch (Error | RuntimeException exception) {
+                } catch (Throwable exception) {
                   ArrayList<Object> wrappedError = wrapError(exception);
                   wrapped = wrappedError;
                 }
@@ -2640,14 +2390,15 @@
     String getAssetFilePathByName(@NonNull String name);
 
     /** The codec used by FlutterAssetManagerHostApi. */
-    static MessageCodec<Object> getCodec() {
+    static @NonNull MessageCodec<Object> getCodec() {
       return new StandardMessageCodec();
     }
     /**
      * Sets up an instance of `FlutterAssetManagerHostApi` to handle messages through the
      * `binaryMessenger`.
      */
-    static void setup(BinaryMessenger binaryMessenger, FlutterAssetManagerHostApi api) {
+    static void setup(
+        @NonNull BinaryMessenger binaryMessenger, @Nullable FlutterAssetManagerHostApi api) {
       {
         BasicMessageChannel<Object> channel =
             new BasicMessageChannel<>(
@@ -2656,16 +2407,12 @@
           channel.setMessageHandler(
               (message, reply) -> {
                 ArrayList<Object> wrapped = new ArrayList<Object>();
+                ArrayList<Object> args = (ArrayList<Object>) message;
+                String pathArg = (String) args.get(0);
                 try {
-                  ArrayList<Object> args = (ArrayList<Object>) message;
-                  assert args != null;
-                  String pathArg = (String) args.get(0);
-                  if (pathArg == null) {
-                    throw new NullPointerException("pathArg unexpectedly null.");
-                  }
                   List<String> output = api.list(pathArg);
                   wrapped.add(0, output);
-                } catch (Error | RuntimeException exception) {
+                } catch (Throwable exception) {
                   ArrayList<Object> wrappedError = wrapError(exception);
                   wrapped = wrappedError;
                 }
@@ -2685,16 +2432,12 @@
           channel.setMessageHandler(
               (message, reply) -> {
                 ArrayList<Object> wrapped = new ArrayList<Object>();
+                ArrayList<Object> args = (ArrayList<Object>) message;
+                String nameArg = (String) args.get(0);
                 try {
-                  ArrayList<Object> args = (ArrayList<Object>) message;
-                  assert args != null;
-                  String nameArg = (String) args.get(0);
-                  if (nameArg == null) {
-                    throw new NullPointerException("nameArg unexpectedly null.");
-                  }
                   String output = api.getAssetFilePathByName(nameArg);
                   wrapped.add(0, output);
-                } catch (Error | RuntimeException exception) {
+                } catch (Throwable exception) {
                   ArrayList<Object> wrappedError = wrapError(exception);
                   wrapped = wrappedError;
                 }
@@ -2708,18 +2451,19 @@
   }
   /** Generated class from Pigeon that represents Flutter messages that can be called from Java. */
   public static class WebChromeClientFlutterApi {
-    private final BinaryMessenger binaryMessenger;
+    private final @NonNull BinaryMessenger binaryMessenger;
 
-    public WebChromeClientFlutterApi(BinaryMessenger argBinaryMessenger) {
+    public WebChromeClientFlutterApi(@NonNull BinaryMessenger argBinaryMessenger) {
       this.binaryMessenger = argBinaryMessenger;
     }
 
     /** Public interface for sending reply. */
+    @SuppressWarnings("UnknownNullness")
     public interface Reply<T> {
       void reply(T reply);
     }
     /** The codec used by WebChromeClientFlutterApi. */
-    static MessageCodec<Object> getCodec() {
+    static @NonNull MessageCodec<Object> getCodec() {
       return new StandardMessageCodec();
     }
 
@@ -2727,7 +2471,7 @@
         @NonNull Long instanceIdArg,
         @NonNull Long webViewInstanceIdArg,
         @NonNull Long progressArg,
-        Reply<Void> callback) {
+        @NonNull Reply<Void> callback) {
       BasicMessageChannel<Object> channel =
           new BasicMessageChannel<>(
               binaryMessenger,
@@ -2742,7 +2486,7 @@
         @NonNull Long instanceIdArg,
         @NonNull Long webViewInstanceIdArg,
         @NonNull Long paramsInstanceIdArg,
-        Reply<List<String>> callback) {
+        @NonNull Reply<List<String>> callback) {
       BasicMessageChannel<Object> channel =
           new BasicMessageChannel<>(
               binaryMessenger,
@@ -2766,13 +2510,13 @@
     void deleteAllData(@NonNull Long instanceId);
 
     /** The codec used by WebStorageHostApi. */
-    static MessageCodec<Object> getCodec() {
+    static @NonNull MessageCodec<Object> getCodec() {
       return new StandardMessageCodec();
     }
     /**
      * Sets up an instance of `WebStorageHostApi` to handle messages through the `binaryMessenger`.
      */
-    static void setup(BinaryMessenger binaryMessenger, WebStorageHostApi api) {
+    static void setup(@NonNull BinaryMessenger binaryMessenger, @Nullable WebStorageHostApi api) {
       {
         BasicMessageChannel<Object> channel =
             new BasicMessageChannel<>(
@@ -2781,16 +2525,12 @@
           channel.setMessageHandler(
               (message, reply) -> {
                 ArrayList<Object> wrapped = new ArrayList<Object>();
+                ArrayList<Object> args = (ArrayList<Object>) message;
+                Number instanceIdArg = (Number) args.get(0);
                 try {
-                  ArrayList<Object> args = (ArrayList<Object>) message;
-                  assert args != null;
-                  Number instanceIdArg = (Number) args.get(0);
-                  if (instanceIdArg == null) {
-                    throw new NullPointerException("instanceIdArg unexpectedly null.");
-                  }
                   api.create((instanceIdArg == null) ? null : instanceIdArg.longValue());
                   wrapped.add(0, null);
-                } catch (Error | RuntimeException exception) {
+                } catch (Throwable exception) {
                   ArrayList<Object> wrappedError = wrapError(exception);
                   wrapped = wrappedError;
                 }
@@ -2808,16 +2548,12 @@
           channel.setMessageHandler(
               (message, reply) -> {
                 ArrayList<Object> wrapped = new ArrayList<Object>();
+                ArrayList<Object> args = (ArrayList<Object>) message;
+                Number instanceIdArg = (Number) args.get(0);
                 try {
-                  ArrayList<Object> args = (ArrayList<Object>) message;
-                  assert args != null;
-                  Number instanceIdArg = (Number) args.get(0);
-                  if (instanceIdArg == null) {
-                    throw new NullPointerException("instanceIdArg unexpectedly null.");
-                  }
                   api.deleteAllData((instanceIdArg == null) ? null : instanceIdArg.longValue());
                   wrapped.add(0, null);
-                } catch (Error | RuntimeException exception) {
+                } catch (Throwable exception) {
                   ArrayList<Object> wrappedError = wrapError(exception);
                   wrapped = wrappedError;
                 }
@@ -2866,18 +2602,19 @@
    * <p>Generated class from Pigeon that represents Flutter messages that can be called from Java.
    */
   public static class FileChooserParamsFlutterApi {
-    private final BinaryMessenger binaryMessenger;
+    private final @NonNull BinaryMessenger binaryMessenger;
 
-    public FileChooserParamsFlutterApi(BinaryMessenger argBinaryMessenger) {
+    public FileChooserParamsFlutterApi(@NonNull BinaryMessenger argBinaryMessenger) {
       this.binaryMessenger = argBinaryMessenger;
     }
 
     /** Public interface for sending reply. */
+    @SuppressWarnings("UnknownNullness")
     public interface Reply<T> {
       void reply(T reply);
     }
     /** The codec used by FileChooserParamsFlutterApi. */
-    static MessageCodec<Object> getCodec() {
+    static @NonNull MessageCodec<Object> getCodec() {
       return FileChooserParamsFlutterApiCodec.INSTANCE;
     }
 
@@ -2887,7 +2624,7 @@
         @NonNull List<String> acceptTypesArg,
         @NonNull FileChooserModeEnumData modeArg,
         @Nullable String filenameHintArg,
-        Reply<Void> callback) {
+        @NonNull Reply<Void> callback) {
       BasicMessageChannel<Object> channel =
           new BasicMessageChannel<>(
               binaryMessenger, "dev.flutter.pigeon.FileChooserParamsFlutterApi.create", getCodec());
diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewClientFlutterApiImpl.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewClientFlutterApiImpl.java
index aad569d..6893af9 100644
--- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewClientFlutterApiImpl.java
+++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewClientFlutterApiImpl.java
@@ -10,6 +10,7 @@
 import android.webkit.WebResourceRequest;
 import android.webkit.WebView;
 import android.webkit.WebViewClient;
+import androidx.annotation.NonNull;
 import androidx.annotation.RequiresApi;
 import androidx.webkit.WebResourceErrorCompat;
 import io.flutter.plugin.common.BinaryMessenger;
@@ -202,6 +203,21 @@
     urlLoading(getIdentifierForClient(webViewClient), webViewIdentifier, urlArg, callback);
   }
 
+  /** Passes arguments from {@link WebViewClient#doUpdateVisitedHistory} to Dart. */
+  public void doUpdateVisitedHistory(
+      @NonNull WebViewClient webViewClient,
+      @NonNull WebView webView,
+      @NonNull String url,
+      boolean isReload,
+      @NonNull Reply<Void> callback) {
+    webViewFlutterApi.create(webView, reply -> {});
+
+    final Long webViewIdentifier =
+        Objects.requireNonNull(instanceManager.getIdentifierForStrongReference(webView));
+    doUpdateVisitedHistory(
+        getIdentifierForClient(webViewClient), webViewIdentifier, url, isReload, callback);
+  }
+
   private long getIdentifierForClient(WebViewClient webViewClient) {
     final Long identifier = instanceManager.getIdentifierForStrongReference(webViewClient);
     if (identifier == null) {
diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewClientHostApiImpl.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewClientHostApiImpl.java
index 79c0210..b5764f4 100644
--- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewClientHostApiImpl.java
+++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewClientHostApiImpl.java
@@ -83,6 +83,11 @@
     }
 
     @Override
+    public void doUpdateVisitedHistory(WebView view, String url, boolean isReload) {
+      flutterApi.doUpdateVisitedHistory(this, view, url, isReload, reply -> {});
+    }
+
+    @Override
     public void onUnhandledKeyEvent(WebView view, KeyEvent event) {
       // Deliberately empty. Occasionally the webview will mark events as having failed to be
       // handled even though they were handled. We don't want to propagate those as they're not
@@ -155,7 +160,12 @@
     }
 
     @Override
-    public void onUnhandledKeyEvent(WebView view, KeyEvent event) {
+    public void doUpdateVisitedHistory(WebView view, String url, boolean isReload) {
+      flutterApi.doUpdateVisitedHistory(this, view, url, isReload, reply -> {});
+    }
+
+    @Override
+    public void onUnhandledKeyEvent(@NonNull WebView view, @NonNull KeyEvent event) {
       // Deliberately empty. Occasionally the webview will mark events as having failed to be
       // handled even though they were handled. We don't want to propagate those as they're not
       // truly lost.
@@ -175,7 +185,8 @@
      * @param flutterApi handles sending messages to Dart
      * @return the created {@link WebViewClient}
      */
-    public WebViewClient createWebViewClient(WebViewClientFlutterApiImpl flutterApi) {
+    @NonNull
+    public WebViewClient createWebViewClient(@NonNull WebViewClientFlutterApiImpl flutterApi) {
       // WebViewClientCompat is used to get
       // shouldOverrideUrlLoading(WebView view, WebResourceRequest request)
       // invoked by the webview on older Android devices, without it pages that use iframes will
diff --git a/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebViewClientTest.java b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebViewClientTest.java
index f9e836e..2462ef3 100644
--- a/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebViewClientTest.java
+++ b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebViewClientTest.java
@@ -15,6 +15,7 @@
 import android.webkit.WebResourceRequest;
 import android.webkit.WebView;
 import android.webkit.WebViewClient;
+import androidx.annotation.NonNull;
 import io.flutter.plugins.webviewflutter.WebViewClientHostApiImpl.WebViewClientCompatImpl;
 import io.flutter.plugins.webviewflutter.WebViewClientHostApiImpl.WebViewClientCreator;
 import java.util.HashMap;
@@ -111,8 +112,10 @@
         new WebViewClientHostApiImpl(
             instanceManager,
             new WebViewClientCreator() {
+              @NonNull
               @Override
-              public WebViewClient createWebViewClient(WebViewClientFlutterApiImpl flutterApi) {
+              public WebViewClient createWebViewClient(
+                  @NonNull WebViewClientFlutterApiImpl flutterApi) {
                 return mockWebViewClient;
               }
             },
@@ -123,4 +126,12 @@
 
     verify(mockWebViewClient).setReturnValueForShouldOverrideUrlLoading(false);
   }
+
+  @Test
+  public void doUpdateVisitedHistory() {
+    webViewClient.doUpdateVisitedHistory(mockWebView, "https://www.google.com", true);
+    verify(mockFlutterApi)
+        .doUpdateVisitedHistory(
+            eq(webViewClient), eq(mockWebView), eq("https://www.google.com"), eq(true), any());
+  }
 }
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 4ec7ae8..188687b 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
@@ -942,6 +942,81 @@
       final String? currentUrl = await controller.currentUrl();
       expect(currentUrl, secondaryUrl);
     });
+
+    testWidgets('can receive url changes', (WidgetTester tester) async {
+      final Completer<void> pageLoaded = Completer<void>();
+
+      final PlatformNavigationDelegate navigationDelegate =
+          PlatformNavigationDelegate(
+        const PlatformNavigationDelegateCreationParams(),
+      )..setOnPageFinished((_) => pageLoaded.complete());
+
+      final PlatformWebViewController controller = PlatformWebViewController(
+        const PlatformWebViewControllerCreationParams(),
+      )
+        ..setJavaScriptMode(JavaScriptMode.unrestricted)
+        ..setPlatformNavigationDelegate(navigationDelegate)
+        ..loadRequest(LoadRequestParams(uri: Uri.parse(blankPageEncoded)));
+
+      await tester.pumpWidget(Builder(
+        builder: (BuildContext context) {
+          return PlatformWebViewWidget(
+            PlatformWebViewWidgetCreationParams(controller: controller),
+          ).build(context);
+        },
+      ));
+
+      await pageLoaded.future;
+      await navigationDelegate.setOnPageFinished((_) {});
+
+      final Completer<String> urlChangeCompleter = Completer<String>();
+      await navigationDelegate.setOnUrlChange((UrlChange change) {
+        urlChangeCompleter.complete(change.url);
+      });
+
+      await controller.runJavaScript('location.href = "$primaryUrl"');
+
+      await expectLater(urlChangeCompleter.future, completion(primaryUrl));
+    });
+
+    testWidgets('can receive updates to history state',
+        (WidgetTester tester) async {
+      final Completer<void> pageLoaded = Completer<void>();
+
+      final PlatformNavigationDelegate navigationDelegate =
+          PlatformNavigationDelegate(
+        const PlatformNavigationDelegateCreationParams(),
+      )..setOnPageFinished((_) => pageLoaded.complete());
+
+      final PlatformWebViewController controller = PlatformWebViewController(
+        const PlatformWebViewControllerCreationParams(),
+      )
+        ..setJavaScriptMode(JavaScriptMode.unrestricted)
+        ..setPlatformNavigationDelegate(navigationDelegate)
+        ..loadRequest(LoadRequestParams(uri: Uri.parse(primaryUrl)));
+
+      await tester.pumpWidget(Builder(
+        builder: (BuildContext context) {
+          return PlatformWebViewWidget(
+            PlatformWebViewWidgetCreationParams(controller: controller),
+          ).build(context);
+        },
+      ));
+
+      await pageLoaded.future;
+      await navigationDelegate.setOnPageFinished((_) {});
+
+      final Completer<String> urlChangeCompleter = Completer<String>();
+      await navigationDelegate.setOnUrlChange((UrlChange change) {
+        urlChangeCompleter.complete(change.url);
+      });
+
+      await controller.runJavaScript(
+        'window.history.pushState({}, "", "secondary.txt");',
+      );
+
+      await expectLater(urlChangeCompleter.future, completion(secondaryUrl));
+    });
   });
 
   testWidgets('target _blank opens in same window',
diff --git a/packages/webview_flutter/webview_flutter_android/example/lib/main.dart b/packages/webview_flutter/webview_flutter_android/example/lib/main.dart
index 3c6a514..b8c9f7b 100644
--- a/packages/webview_flutter/webview_flutter_android/example/lib/main.dart
+++ b/packages/webview_flutter/webview_flutter_android/example/lib/main.dart
@@ -123,6 +123,9 @@
             }
             debugPrint('allowing navigation to ${request.url}');
             return NavigationDecision.navigate;
+          })
+          ..setOnUrlChange((UrlChange change) {
+            debugPrint('url change to ${change.url}');
           }),
       )
       ..addJavaScriptChannel(JavaScriptChannelParams(
diff --git a/packages/webview_flutter/webview_flutter_android/example/pubspec.yaml b/packages/webview_flutter/webview_flutter_android/example/pubspec.yaml
index 83f3f00..8a190ff 100644
--- a/packages/webview_flutter/webview_flutter_android/example/pubspec.yaml
+++ b/packages/webview_flutter/webview_flutter_android/example/pubspec.yaml
@@ -19,7 +19,7 @@
     # The example app is bundled with the plugin so we use a path dependency on
     # the parent directory to use the current plugin's version.
     path: ../
-  webview_flutter_platform_interface: ^2.0.0
+  webview_flutter_platform_interface: ^2.1.0
 
 dev_dependencies:
   espresso: ^0.2.0
diff --git a/packages/webview_flutter/webview_flutter_android/lib/src/android_proxy.dart b/packages/webview_flutter/webview_flutter_android/lib/src/android_proxy.dart
index a6505c2..0d71622 100644
--- a/packages/webview_flutter/webview_flutter_android/lib/src/android_proxy.dart
+++ b/packages/webview_flutter/webview_flutter_android/lib/src/android_proxy.dart
@@ -58,6 +58,8 @@
       android_webview.WebResourceRequest request,
     )? requestLoading,
     void Function(android_webview.WebView webView, String url)? urlLoading,
+    void Function(android_webview.WebView webView, String url, bool isReload)?
+        doUpdateVisitedHistory,
   }) createAndroidWebViewClient;
 
   /// Constructs a [android_webview.FlutterAssetManager].
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 5c55209..8ab89d4 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
@@ -677,6 +677,7 @@
     @Deprecated('Only called on Android version < 23.') this.onReceivedError,
     this.requestLoading,
     this.urlLoading,
+    this.doUpdateVisitedHistory,
     @visibleForTesting super.binaryMessenger,
     @visibleForTesting super.instanceManager,
   }) : super.detached() {
@@ -696,6 +697,7 @@
     @Deprecated('Only called on Android version < 23.') this.onReceivedError,
     this.requestLoading,
     this.urlLoading,
+    this.doUpdateVisitedHistory,
     super.binaryMessenger,
     super.instanceManager,
   }) : super.detached();
@@ -840,6 +842,10 @@
   /// indicates whether the [WebView] loaded the URL.
   final void Function(WebView webView, String url)? urlLoading;
 
+  /// Notify the host application to update its visited links database.
+  final void Function(WebView webView, String url, bool isReload)?
+      doUpdateVisitedHistory;
+
   /// Sets the required synchronous return value for the Java method,
   /// `WebViewClient.shouldOverrideUrlLoading(...)`.
   ///
@@ -867,6 +873,7 @@
       onReceivedError: onReceivedError,
       requestLoading: requestLoading,
       urlLoading: urlLoading,
+      doUpdateVisitedHistory: doUpdateVisitedHistory,
       binaryMessenger: _api.binaryMessenger,
       instanceManager: _api.instanceManager,
     );
diff --git a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.g.dart b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.g.dart
index d2976a8..6529284 100644
--- a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.g.dart
+++ b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.g.dart
@@ -1,7 +1,7 @@
 // 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.
-// Autogenerated from Pigeon (v9.0.5), do not edit directly.
+// Autogenerated from Pigeon (v9.2.3), do not edit directly.
 // See also: https://pub.dev/packages/pigeon
 // ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, unused_shown_name, unnecessary_import
 
@@ -1514,6 +1514,9 @@
 
   void urlLoading(int instanceId, int webViewInstanceId, String url);
 
+  void doUpdateVisitedHistory(
+      int instanceId, int webViewInstanceId, String url, bool isReload);
+
   static void setup(WebViewClientFlutterApi? api,
       {BinaryMessenger? binaryMessenger}) {
     {
@@ -1682,6 +1685,36 @@
         });
       }
     }
+    {
+      final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
+          'dev.flutter.pigeon.WebViewClientFlutterApi.doUpdateVisitedHistory',
+          codec,
+          binaryMessenger: binaryMessenger);
+      if (api == null) {
+        channel.setMessageHandler(null);
+      } else {
+        channel.setMessageHandler((Object? message) async {
+          assert(message != null,
+              'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.doUpdateVisitedHistory was null.');
+          final List<Object?> args = (message as List<Object?>?)!;
+          final int? arg_instanceId = (args[0] as int?);
+          assert(arg_instanceId != null,
+              'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.doUpdateVisitedHistory was null, expected non-null int.');
+          final int? arg_webViewInstanceId = (args[1] as int?);
+          assert(arg_webViewInstanceId != null,
+              'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.doUpdateVisitedHistory was null, expected non-null int.');
+          final String? arg_url = (args[2] as String?);
+          assert(arg_url != null,
+              'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.doUpdateVisitedHistory was null, expected non-null String.');
+          final bool? arg_isReload = (args[3] as bool?);
+          assert(arg_isReload != null,
+              'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.doUpdateVisitedHistory was null, expected non-null bool.');
+          api.doUpdateVisitedHistory(
+              arg_instanceId!, arg_webViewInstanceId!, arg_url!, arg_isReload!);
+          return;
+        });
+      }
+    }
   }
 }
 
diff --git a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_api_impls.dart b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_api_impls.dart
index 721caf7..0bc2c84 100644
--- a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_api_impls.dart
+++ b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_api_impls.dart
@@ -754,6 +754,30 @@
       instance.urlLoading!(webViewInstance!, url);
     }
   }
+
+  @override
+  void doUpdateVisitedHistory(
+    int instanceId,
+    int webViewInstanceId,
+    String url,
+    bool isReload,
+  ) {
+    final WebViewClient? instance = instanceManager
+        .getInstanceWithWeakReference(instanceId) as WebViewClient?;
+    final WebView? webViewInstance = instanceManager
+        .getInstanceWithWeakReference(webViewInstanceId) as WebView?;
+    assert(
+      instance != null,
+      'InstanceManager does not contain an WebViewClient with instanceId: $instanceId',
+    );
+    assert(
+      webViewInstance != null,
+      'InstanceManager does not contain an WebView with instanceId: $webViewInstanceId',
+    );
+    if (instance!.doUpdateVisitedHistory != null) {
+      instance.doUpdateVisitedHistory!(webViewInstance!, url, isReload);
+    }
+  }
 }
 
 /// Host api implementation for [DownloadListener].
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 f1fe168..88a4bca 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
@@ -704,6 +704,15 @@
   final AndroidWebViewProxy androidWebViewProxy;
 }
 
+/// Android details of the change to a web view's url.
+class AndroidUrlChange extends UrlChange {
+  /// Constructs an [AndroidUrlChange].
+  const AndroidUrlChange({required super.url, required this.isReload});
+
+  /// Whether the url is being reloaded.
+  final bool isReload;
+}
+
 /// A place to register callback methods responsible to handle navigation events
 /// triggered by the [android_webview.WebView].
 class AndroidNavigationDelegate extends PlatformNavigationDelegate {
@@ -720,13 +729,15 @@
         .androidWebViewProxy
         .createAndroidWebViewClient(
       onPageFinished: (android_webview.WebView webView, String url) {
-        if (weakThis.target?._onPageFinished != null) {
-          weakThis.target!._onPageFinished!(url);
+        final PageEventCallback? callback = weakThis.target?._onPageFinished;
+        if (callback != null) {
+          callback(url);
         }
       },
       onPageStarted: (android_webview.WebView webView, String url) {
-        if (weakThis.target?._onPageStarted != null) {
-          weakThis.target!._onPageStarted!(url);
+        final PageEventCallback? callback = weakThis.target?._onPageStarted;
+        if (callback != null) {
+          callback(url);
         }
       },
       onReceivedRequestError: (
@@ -734,8 +745,10 @@
         android_webview.WebResourceRequest request,
         android_webview.WebResourceError error,
       ) {
-        if (weakThis.target?._onWebResourceError != null) {
-          weakThis.target!._onWebResourceError!(AndroidWebResourceError._(
+        final WebResourceErrorCallback? callback =
+            weakThis.target?._onWebResourceError;
+        if (callback != null) {
+          callback(AndroidWebResourceError._(
             errorCode: error.errorCode,
             description: error.description,
             failingUrl: request.url,
@@ -749,8 +762,10 @@
         String description,
         String failingUrl,
       ) {
-        if (weakThis.target?._onWebResourceError != null) {
-          weakThis.target!._onWebResourceError!(AndroidWebResourceError._(
+        final WebResourceErrorCallback? callback =
+            weakThis.target?._onWebResourceError;
+        if (callback != null) {
+          callback(AndroidWebResourceError._(
             errorCode: errorCode,
             description: description,
             failingUrl: failingUrl,
@@ -762,20 +777,23 @@
         android_webview.WebView webView,
         android_webview.WebResourceRequest request,
       ) {
-        if (weakThis.target != null) {
-          weakThis.target!._handleNavigation(
-            request.url,
-            headers: request.requestHeaders,
-            isForMainFrame: request.isForMainFrame,
-          );
-        }
+        weakThis.target?._handleNavigation(
+          request.url,
+          headers: request.requestHeaders,
+          isForMainFrame: request.isForMainFrame,
+        );
       },
-      urlLoading: (
+      urlLoading: (android_webview.WebView webView, String url) {
+        weakThis.target?._handleNavigation(url, isForMainFrame: true);
+      },
+      doUpdateVisitedHistory: (
         android_webview.WebView webView,
         String url,
+        bool isReload,
       ) {
-        if (weakThis.target != null) {
-          weakThis.target!._handleNavigation(url, isForMainFrame: true);
+        final UrlChangeCallback? callback = weakThis.target?._onUrlChange;
+        if (callback != null) {
+          callback(AndroidUrlChange(url: url, isReload: isReload));
         }
       },
     );
@@ -833,6 +851,7 @@
   WebResourceErrorCallback? _onWebResourceError;
   NavigationRequestCallback? _onNavigationRequest;
   LoadRequestCallback? _onLoadRequest;
+  UrlChangeCallback? _onUrlChange;
 
   void _handleNavigation(
     String url, {
@@ -913,4 +932,9 @@
   ) async {
     _onWebResourceError = onWebResourceError;
   }
+
+  @override
+  Future<void> setOnUrlChange(UrlChangeCallback onUrlChange) async {
+    _onUrlChange = onUrlChange;
+  }
 }
diff --git a/packages/webview_flutter/webview_flutter_android/pigeons/android_webview.dart b/packages/webview_flutter/webview_flutter_android/pigeons/android_webview.dart
index 9978ed4..1d232b2 100644
--- a/packages/webview_flutter/webview_flutter_android/pigeons/android_webview.dart
+++ b/packages/webview_flutter/webview_flutter_android/pigeons/android_webview.dart
@@ -292,6 +292,13 @@
   );
 
   void urlLoading(int instanceId, int webViewInstanceId, String url);
+
+  void doUpdateVisitedHistory(
+    int instanceId,
+    int webViewInstanceId,
+    String url,
+    bool isReload,
+  );
 }
 
 @HostApi(dartHostTestHandler: 'TestDownloadListenerHostApi')
diff --git a/packages/webview_flutter/webview_flutter_android/pubspec.yaml b/packages/webview_flutter/webview_flutter_android/pubspec.yaml
index 37b3826..7eb5411 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/packages/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.4.5
+version: 3.5.0
 
 environment:
   sdk: ">=2.18.0 <4.0.0"
@@ -20,7 +20,7 @@
 dependencies:
   flutter:
     sdk: flutter
-  webview_flutter_platform_interface: ^2.0.0
+  webview_flutter_platform_interface: ^2.1.0
 
 dev_dependencies:
   build_runner: ^2.1.4
diff --git a/packages/webview_flutter/webview_flutter_android/test/android_navigation_delegate_test.dart b/packages/webview_flutter/webview_flutter_android/test/android_navigation_delegate_test.dart
index 2bf563b..1801589 100644
--- a/packages/webview_flutter/webview_flutter_android/test/android_navigation_delegate_test.dart
+++ b/packages/webview_flutter/webview_flutter_android/test/android_navigation_delegate_test.dart
@@ -447,6 +447,27 @@
       expect(completer.isCompleted, true);
     });
   });
+
+  test('onUrlChange', () {
+    final AndroidNavigationDelegate androidNavigationDelegate =
+        AndroidNavigationDelegate(_buildCreationParams());
+
+    late final AndroidUrlChange urlChange;
+    androidNavigationDelegate.setOnUrlChange(
+      (UrlChange change) {
+        urlChange = change as AndroidUrlChange;
+      },
+    );
+
+    CapturingWebViewClient.lastCreatedDelegate.doUpdateVisitedHistory!(
+      android_webview.WebView.detached(),
+      'https://www.google.com',
+      false,
+    );
+
+    expect(urlChange.url, 'https://www.google.com');
+    expect(urlChange.isReload, isFalse);
+  });
 }
 
 AndroidNavigationDelegateCreationParams _buildCreationParams() {
@@ -471,6 +492,7 @@
     super.onReceivedRequestError,
     super.requestLoading,
     super.urlLoading,
+    super.doUpdateVisitedHistory,
     super.binaryMessenger,
     super.instanceManager,
   }) : super.detached() {
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 78e3144..f224ff1 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
@@ -105,6 +105,11 @@
                 )? requestLoading,
                 void Function(android_webview.WebView webView, String url)?
                     urlLoading,
+                void Function(
+                  android_webview.WebView webView,
+                  String url,
+                  bool isReload,
+                )? doUpdateVisitedHistory,
               }) =>
                   mockWebViewClient ?? MockWebViewClient(),
               createFlutterAssetManager: () =>
diff --git a/packages/webview_flutter/webview_flutter_android/test/android_webview_controller_test.mocks.dart b/packages/webview_flutter/webview_flutter_android/test/android_webview_controller_test.mocks.dart
index 595db88..e0c637e 100644
--- a/packages/webview_flutter/webview_flutter_android/test/android_webview_controller_test.mocks.dart
+++ b/packages/webview_flutter/webview_flutter_android/test/android_webview_controller_test.mocks.dart
@@ -760,6 +760,11 @@
     void Function(
       _i2.WebView,
       String,
+      bool,
+    )? doUpdateVisitedHistory,
+    void Function(
+      _i2.WebView,
+      String,
     )? onPageFinished,
     void Function(
       _i2.WebView,
@@ -790,6 +795,11 @@
           void Function(
             _i2.WebView,
             String,
+            bool,
+          )? doUpdateVisitedHistory,
+          void Function(
+            _i2.WebView,
+            String,
           )? onPageFinished,
           void Function(
             _i2.WebView,
@@ -823,6 +833,11 @@
           void Function(
             _i2.WebView,
             String,
+            bool,
+          )? doUpdateVisitedHistory,
+          void Function(
+            _i2.WebView,
+            String,
           )? onPageFinished,
           void Function(
             _i2.WebView,
@@ -856,6 +871,11 @@
         void Function(
           _i2.WebView,
           String,
+          bool,
+        )? doUpdateVisitedHistory,
+        void Function(
+          _i2.WebView,
+          String,
         )? onPageFinished,
         void Function(
           _i2.WebView,
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 f447926..71c30b6 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
@@ -739,6 +739,33 @@
         );
       });
 
+      test('doUpdateVisitedHistory', () {
+        late final List<Object> result;
+        when(mockWebViewClient.doUpdateVisitedHistory).thenReturn(
+          (
+            WebView webView,
+            String url,
+            bool isReload,
+          ) {
+            result = <Object>[webView, url, isReload];
+          },
+        );
+
+        flutterApi.doUpdateVisitedHistory(
+          mockWebViewClientInstanceId,
+          mockWebViewInstanceId,
+          'https://www.google.com',
+          false,
+        );
+
+        expect(
+          result,
+          containsAllInOrder(
+            <Object?>[mockWebView, 'https://www.google.com', false],
+          ),
+        );
+      });
+
       test('copy', () {
         expect(WebViewClient.detached().copy(), isA<WebViewClient>());
       });
diff --git a/packages/webview_flutter/webview_flutter_android/test/test_android_webview.g.dart b/packages/webview_flutter/webview_flutter_android/test/test_android_webview.g.dart
index 33ab0ec..5857a09 100644
--- a/packages/webview_flutter/webview_flutter_android/test/test_android_webview.g.dart
+++ b/packages/webview_flutter/webview_flutter_android/test/test_android_webview.g.dart
@@ -1,7 +1,7 @@
 // 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.
-// Autogenerated from Pigeon (v9.0.5), do not edit directly.
+// Autogenerated from Pigeon (v9.2.3), do not edit directly.
 // See also: https://pub.dev/packages/pigeon
 // ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, unnecessary_import
 // ignore_for_file: avoid_relative_lib_imports
@@ -15,6 +15,8 @@
 
 /// Host API for managing the native `InstanceManager`.
 abstract class TestInstanceManagerHostApi {
+  static TestDefaultBinaryMessengerBinding? get _testBinaryMessengerBinding =>
+      TestDefaultBinaryMessengerBinding.instance;
   static const MessageCodec<Object?> codec = StandardMessageCodec();
 
   /// Clear the native `InstanceManager`.
@@ -29,9 +31,12 @@
           'dev.flutter.pigeon.InstanceManagerHostApi.clear', codec,
           binaryMessenger: binaryMessenger);
       if (api == null) {
-        channel.setMockMessageHandler(null);
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel, null);
       } else {
-        channel.setMockMessageHandler((Object? message) async {
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel,
+                (Object? message) async {
           // ignore message
           api.clear();
           return <Object?>[];
@@ -47,6 +52,8 @@
 ///
 /// See https://docs.oracle.com/javase/7/docs/api/java/lang/Object.html.
 abstract class TestJavaObjectHostApi {
+  static TestDefaultBinaryMessengerBinding? get _testBinaryMessengerBinding =>
+      TestDefaultBinaryMessengerBinding.instance;
   static const MessageCodec<Object?> codec = StandardMessageCodec();
 
   void dispose(int identifier);
@@ -58,9 +65,12 @@
           'dev.flutter.pigeon.JavaObjectHostApi.dispose', codec,
           binaryMessenger: binaryMessenger);
       if (api == null) {
-        channel.setMockMessageHandler(null);
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel, null);
       } else {
-        channel.setMockMessageHandler((Object? message) async {
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel,
+                (Object? message) async {
           assert(message != null,
               'Argument for dev.flutter.pigeon.JavaObjectHostApi.dispose was null.');
           final List<Object?> args = (message as List<Object?>?)!;
@@ -99,6 +109,8 @@
 }
 
 abstract class TestWebViewHostApi {
+  static TestDefaultBinaryMessengerBinding? get _testBinaryMessengerBinding =>
+      TestDefaultBinaryMessengerBinding.instance;
   static const MessageCodec<Object?> codec = _TestWebViewHostApiCodec();
 
   void create(int instanceId);
@@ -162,9 +174,12 @@
           'dev.flutter.pigeon.WebViewHostApi.create', codec,
           binaryMessenger: binaryMessenger);
       if (api == null) {
-        channel.setMockMessageHandler(null);
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel, null);
       } else {
-        channel.setMockMessageHandler((Object? message) async {
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel,
+                (Object? message) async {
           assert(message != null,
               'Argument for dev.flutter.pigeon.WebViewHostApi.create was null.');
           final List<Object?> args = (message as List<Object?>?)!;
@@ -181,9 +196,12 @@
           'dev.flutter.pigeon.WebViewHostApi.loadData', codec,
           binaryMessenger: binaryMessenger);
       if (api == null) {
-        channel.setMockMessageHandler(null);
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel, null);
       } else {
-        channel.setMockMessageHandler((Object? message) async {
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel,
+                (Object? message) async {
           assert(message != null,
               'Argument for dev.flutter.pigeon.WebViewHostApi.loadData was null.');
           final List<Object?> args = (message as List<Object?>?)!;
@@ -205,9 +223,12 @@
           'dev.flutter.pigeon.WebViewHostApi.loadDataWithBaseUrl', codec,
           binaryMessenger: binaryMessenger);
       if (api == null) {
-        channel.setMockMessageHandler(null);
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel, null);
       } else {
-        channel.setMockMessageHandler((Object? message) async {
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel,
+                (Object? message) async {
           assert(message != null,
               'Argument for dev.flutter.pigeon.WebViewHostApi.loadDataWithBaseUrl was null.');
           final List<Object?> args = (message as List<Object?>?)!;
@@ -232,9 +253,12 @@
           'dev.flutter.pigeon.WebViewHostApi.loadUrl', codec,
           binaryMessenger: binaryMessenger);
       if (api == null) {
-        channel.setMockMessageHandler(null);
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel, null);
       } else {
-        channel.setMockMessageHandler((Object? message) async {
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel,
+                (Object? message) async {
           assert(message != null,
               'Argument for dev.flutter.pigeon.WebViewHostApi.loadUrl was null.');
           final List<Object?> args = (message as List<Object?>?)!;
@@ -258,9 +282,12 @@
           'dev.flutter.pigeon.WebViewHostApi.postUrl', codec,
           binaryMessenger: binaryMessenger);
       if (api == null) {
-        channel.setMockMessageHandler(null);
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel, null);
       } else {
-        channel.setMockMessageHandler((Object? message) async {
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel,
+                (Object? message) async {
           assert(message != null,
               'Argument for dev.flutter.pigeon.WebViewHostApi.postUrl was null.');
           final List<Object?> args = (message as List<Object?>?)!;
@@ -283,9 +310,12 @@
           'dev.flutter.pigeon.WebViewHostApi.getUrl', codec,
           binaryMessenger: binaryMessenger);
       if (api == null) {
-        channel.setMockMessageHandler(null);
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel, null);
       } else {
-        channel.setMockMessageHandler((Object? message) async {
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel,
+                (Object? message) async {
           assert(message != null,
               'Argument for dev.flutter.pigeon.WebViewHostApi.getUrl was null.');
           final List<Object?> args = (message as List<Object?>?)!;
@@ -302,9 +332,12 @@
           'dev.flutter.pigeon.WebViewHostApi.canGoBack', codec,
           binaryMessenger: binaryMessenger);
       if (api == null) {
-        channel.setMockMessageHandler(null);
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel, null);
       } else {
-        channel.setMockMessageHandler((Object? message) async {
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel,
+                (Object? message) async {
           assert(message != null,
               'Argument for dev.flutter.pigeon.WebViewHostApi.canGoBack was null.');
           final List<Object?> args = (message as List<Object?>?)!;
@@ -321,9 +354,12 @@
           'dev.flutter.pigeon.WebViewHostApi.canGoForward', codec,
           binaryMessenger: binaryMessenger);
       if (api == null) {
-        channel.setMockMessageHandler(null);
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel, null);
       } else {
-        channel.setMockMessageHandler((Object? message) async {
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel,
+                (Object? message) async {
           assert(message != null,
               'Argument for dev.flutter.pigeon.WebViewHostApi.canGoForward was null.');
           final List<Object?> args = (message as List<Object?>?)!;
@@ -340,9 +376,12 @@
           'dev.flutter.pigeon.WebViewHostApi.goBack', codec,
           binaryMessenger: binaryMessenger);
       if (api == null) {
-        channel.setMockMessageHandler(null);
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel, null);
       } else {
-        channel.setMockMessageHandler((Object? message) async {
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel,
+                (Object? message) async {
           assert(message != null,
               'Argument for dev.flutter.pigeon.WebViewHostApi.goBack was null.');
           final List<Object?> args = (message as List<Object?>?)!;
@@ -359,9 +398,12 @@
           'dev.flutter.pigeon.WebViewHostApi.goForward', codec,
           binaryMessenger: binaryMessenger);
       if (api == null) {
-        channel.setMockMessageHandler(null);
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel, null);
       } else {
-        channel.setMockMessageHandler((Object? message) async {
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel,
+                (Object? message) async {
           assert(message != null,
               'Argument for dev.flutter.pigeon.WebViewHostApi.goForward was null.');
           final List<Object?> args = (message as List<Object?>?)!;
@@ -378,9 +420,12 @@
           'dev.flutter.pigeon.WebViewHostApi.reload', codec,
           binaryMessenger: binaryMessenger);
       if (api == null) {
-        channel.setMockMessageHandler(null);
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel, null);
       } else {
-        channel.setMockMessageHandler((Object? message) async {
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel,
+                (Object? message) async {
           assert(message != null,
               'Argument for dev.flutter.pigeon.WebViewHostApi.reload was null.');
           final List<Object?> args = (message as List<Object?>?)!;
@@ -397,9 +442,12 @@
           'dev.flutter.pigeon.WebViewHostApi.clearCache', codec,
           binaryMessenger: binaryMessenger);
       if (api == null) {
-        channel.setMockMessageHandler(null);
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel, null);
       } else {
-        channel.setMockMessageHandler((Object? message) async {
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel,
+                (Object? message) async {
           assert(message != null,
               'Argument for dev.flutter.pigeon.WebViewHostApi.clearCache was null.');
           final List<Object?> args = (message as List<Object?>?)!;
@@ -419,9 +467,12 @@
           'dev.flutter.pigeon.WebViewHostApi.evaluateJavascript', codec,
           binaryMessenger: binaryMessenger);
       if (api == null) {
-        channel.setMockMessageHandler(null);
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel, null);
       } else {
-        channel.setMockMessageHandler((Object? message) async {
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel,
+                (Object? message) async {
           assert(message != null,
               'Argument for dev.flutter.pigeon.WebViewHostApi.evaluateJavascript was null.');
           final List<Object?> args = (message as List<Object?>?)!;
@@ -442,9 +493,12 @@
           'dev.flutter.pigeon.WebViewHostApi.getTitle', codec,
           binaryMessenger: binaryMessenger);
       if (api == null) {
-        channel.setMockMessageHandler(null);
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel, null);
       } else {
-        channel.setMockMessageHandler((Object? message) async {
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel,
+                (Object? message) async {
           assert(message != null,
               'Argument for dev.flutter.pigeon.WebViewHostApi.getTitle was null.');
           final List<Object?> args = (message as List<Object?>?)!;
@@ -461,9 +515,12 @@
           'dev.flutter.pigeon.WebViewHostApi.scrollTo', codec,
           binaryMessenger: binaryMessenger);
       if (api == null) {
-        channel.setMockMessageHandler(null);
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel, null);
       } else {
-        channel.setMockMessageHandler((Object? message) async {
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel,
+                (Object? message) async {
           assert(message != null,
               'Argument for dev.flutter.pigeon.WebViewHostApi.scrollTo was null.');
           final List<Object?> args = (message as List<Object?>?)!;
@@ -486,9 +543,12 @@
           'dev.flutter.pigeon.WebViewHostApi.scrollBy', codec,
           binaryMessenger: binaryMessenger);
       if (api == null) {
-        channel.setMockMessageHandler(null);
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel, null);
       } else {
-        channel.setMockMessageHandler((Object? message) async {
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel,
+                (Object? message) async {
           assert(message != null,
               'Argument for dev.flutter.pigeon.WebViewHostApi.scrollBy was null.');
           final List<Object?> args = (message as List<Object?>?)!;
@@ -511,9 +571,12 @@
           'dev.flutter.pigeon.WebViewHostApi.getScrollX', codec,
           binaryMessenger: binaryMessenger);
       if (api == null) {
-        channel.setMockMessageHandler(null);
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel, null);
       } else {
-        channel.setMockMessageHandler((Object? message) async {
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel,
+                (Object? message) async {
           assert(message != null,
               'Argument for dev.flutter.pigeon.WebViewHostApi.getScrollX was null.');
           final List<Object?> args = (message as List<Object?>?)!;
@@ -530,9 +593,12 @@
           'dev.flutter.pigeon.WebViewHostApi.getScrollY', codec,
           binaryMessenger: binaryMessenger);
       if (api == null) {
-        channel.setMockMessageHandler(null);
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel, null);
       } else {
-        channel.setMockMessageHandler((Object? message) async {
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel,
+                (Object? message) async {
           assert(message != null,
               'Argument for dev.flutter.pigeon.WebViewHostApi.getScrollY was null.');
           final List<Object?> args = (message as List<Object?>?)!;
@@ -549,9 +615,12 @@
           'dev.flutter.pigeon.WebViewHostApi.getScrollPosition', codec,
           binaryMessenger: binaryMessenger);
       if (api == null) {
-        channel.setMockMessageHandler(null);
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel, null);
       } else {
-        channel.setMockMessageHandler((Object? message) async {
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel,
+                (Object? message) async {
           assert(message != null,
               'Argument for dev.flutter.pigeon.WebViewHostApi.getScrollPosition was null.');
           final List<Object?> args = (message as List<Object?>?)!;
@@ -569,9 +638,12 @@
           codec,
           binaryMessenger: binaryMessenger);
       if (api == null) {
-        channel.setMockMessageHandler(null);
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel, null);
       } else {
-        channel.setMockMessageHandler((Object? message) async {
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel,
+                (Object? message) async {
           assert(message != null,
               'Argument for dev.flutter.pigeon.WebViewHostApi.setWebContentsDebuggingEnabled was null.');
           final List<Object?> args = (message as List<Object?>?)!;
@@ -588,9 +660,12 @@
           'dev.flutter.pigeon.WebViewHostApi.setWebViewClient', codec,
           binaryMessenger: binaryMessenger);
       if (api == null) {
-        channel.setMockMessageHandler(null);
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel, null);
       } else {
-        channel.setMockMessageHandler((Object? message) async {
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel,
+                (Object? message) async {
           assert(message != null,
               'Argument for dev.flutter.pigeon.WebViewHostApi.setWebViewClient was null.');
           final List<Object?> args = (message as List<Object?>?)!;
@@ -610,9 +685,12 @@
           'dev.flutter.pigeon.WebViewHostApi.addJavaScriptChannel', codec,
           binaryMessenger: binaryMessenger);
       if (api == null) {
-        channel.setMockMessageHandler(null);
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel, null);
       } else {
-        channel.setMockMessageHandler((Object? message) async {
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel,
+                (Object? message) async {
           assert(message != null,
               'Argument for dev.flutter.pigeon.WebViewHostApi.addJavaScriptChannel was null.');
           final List<Object?> args = (message as List<Object?>?)!;
@@ -633,9 +711,12 @@
           'dev.flutter.pigeon.WebViewHostApi.removeJavaScriptChannel', codec,
           binaryMessenger: binaryMessenger);
       if (api == null) {
-        channel.setMockMessageHandler(null);
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel, null);
       } else {
-        channel.setMockMessageHandler((Object? message) async {
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel,
+                (Object? message) async {
           assert(message != null,
               'Argument for dev.flutter.pigeon.WebViewHostApi.removeJavaScriptChannel was null.');
           final List<Object?> args = (message as List<Object?>?)!;
@@ -656,9 +737,12 @@
           'dev.flutter.pigeon.WebViewHostApi.setDownloadListener', codec,
           binaryMessenger: binaryMessenger);
       if (api == null) {
-        channel.setMockMessageHandler(null);
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel, null);
       } else {
-        channel.setMockMessageHandler((Object? message) async {
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel,
+                (Object? message) async {
           assert(message != null,
               'Argument for dev.flutter.pigeon.WebViewHostApi.setDownloadListener was null.');
           final List<Object?> args = (message as List<Object?>?)!;
@@ -676,9 +760,12 @@
           'dev.flutter.pigeon.WebViewHostApi.setWebChromeClient', codec,
           binaryMessenger: binaryMessenger);
       if (api == null) {
-        channel.setMockMessageHandler(null);
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel, null);
       } else {
-        channel.setMockMessageHandler((Object? message) async {
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel,
+                (Object? message) async {
           assert(message != null,
               'Argument for dev.flutter.pigeon.WebViewHostApi.setWebChromeClient was null.');
           final List<Object?> args = (message as List<Object?>?)!;
@@ -696,9 +783,12 @@
           'dev.flutter.pigeon.WebViewHostApi.setBackgroundColor', codec,
           binaryMessenger: binaryMessenger);
       if (api == null) {
-        channel.setMockMessageHandler(null);
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel, null);
       } else {
-        channel.setMockMessageHandler((Object? message) async {
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel,
+                (Object? message) async {
           assert(message != null,
               'Argument for dev.flutter.pigeon.WebViewHostApi.setBackgroundColor was null.');
           final List<Object?> args = (message as List<Object?>?)!;
@@ -717,6 +807,8 @@
 }
 
 abstract class TestWebSettingsHostApi {
+  static TestDefaultBinaryMessengerBinding? get _testBinaryMessengerBinding =>
+      TestDefaultBinaryMessengerBinding.instance;
   static const MessageCodec<Object?> codec = StandardMessageCodec();
 
   void create(int instanceId, int webViewInstanceId);
@@ -754,9 +846,12 @@
           'dev.flutter.pigeon.WebSettingsHostApi.create', codec,
           binaryMessenger: binaryMessenger);
       if (api == null) {
-        channel.setMockMessageHandler(null);
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel, null);
       } else {
-        channel.setMockMessageHandler((Object? message) async {
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel,
+                (Object? message) async {
           assert(message != null,
               'Argument for dev.flutter.pigeon.WebSettingsHostApi.create was null.');
           final List<Object?> args = (message as List<Object?>?)!;
@@ -776,9 +871,12 @@
           'dev.flutter.pigeon.WebSettingsHostApi.setDomStorageEnabled', codec,
           binaryMessenger: binaryMessenger);
       if (api == null) {
-        channel.setMockMessageHandler(null);
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel, null);
       } else {
-        channel.setMockMessageHandler((Object? message) async {
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel,
+                (Object? message) async {
           assert(message != null,
               'Argument for dev.flutter.pigeon.WebSettingsHostApi.setDomStorageEnabled was null.');
           final List<Object?> args = (message as List<Object?>?)!;
@@ -799,9 +897,12 @@
           codec,
           binaryMessenger: binaryMessenger);
       if (api == null) {
-        channel.setMockMessageHandler(null);
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel, null);
       } else {
-        channel.setMockMessageHandler((Object? message) async {
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel,
+                (Object? message) async {
           assert(message != null,
               'Argument for dev.flutter.pigeon.WebSettingsHostApi.setJavaScriptCanOpenWindowsAutomatically was null.');
           final List<Object?> args = (message as List<Object?>?)!;
@@ -823,9 +924,12 @@
           codec,
           binaryMessenger: binaryMessenger);
       if (api == null) {
-        channel.setMockMessageHandler(null);
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel, null);
       } else {
-        channel.setMockMessageHandler((Object? message) async {
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel,
+                (Object? message) async {
           assert(message != null,
               'Argument for dev.flutter.pigeon.WebSettingsHostApi.setSupportMultipleWindows was null.');
           final List<Object?> args = (message as List<Object?>?)!;
@@ -845,9 +949,12 @@
           'dev.flutter.pigeon.WebSettingsHostApi.setJavaScriptEnabled', codec,
           binaryMessenger: binaryMessenger);
       if (api == null) {
-        channel.setMockMessageHandler(null);
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel, null);
       } else {
-        channel.setMockMessageHandler((Object? message) async {
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel,
+                (Object? message) async {
           assert(message != null,
               'Argument for dev.flutter.pigeon.WebSettingsHostApi.setJavaScriptEnabled was null.');
           final List<Object?> args = (message as List<Object?>?)!;
@@ -867,9 +974,12 @@
           'dev.flutter.pigeon.WebSettingsHostApi.setUserAgentString', codec,
           binaryMessenger: binaryMessenger);
       if (api == null) {
-        channel.setMockMessageHandler(null);
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel, null);
       } else {
-        channel.setMockMessageHandler((Object? message) async {
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel,
+                (Object? message) async {
           assert(message != null,
               'Argument for dev.flutter.pigeon.WebSettingsHostApi.setUserAgentString was null.');
           final List<Object?> args = (message as List<Object?>?)!;
@@ -888,9 +998,12 @@
           codec,
           binaryMessenger: binaryMessenger);
       if (api == null) {
-        channel.setMockMessageHandler(null);
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel, null);
       } else {
-        channel.setMockMessageHandler((Object? message) async {
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel,
+                (Object? message) async {
           assert(message != null,
               'Argument for dev.flutter.pigeon.WebSettingsHostApi.setMediaPlaybackRequiresUserGesture was null.');
           final List<Object?> args = (message as List<Object?>?)!;
@@ -911,9 +1024,12 @@
           'dev.flutter.pigeon.WebSettingsHostApi.setSupportZoom', codec,
           binaryMessenger: binaryMessenger);
       if (api == null) {
-        channel.setMockMessageHandler(null);
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel, null);
       } else {
-        channel.setMockMessageHandler((Object? message) async {
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel,
+                (Object? message) async {
           assert(message != null,
               'Argument for dev.flutter.pigeon.WebSettingsHostApi.setSupportZoom was null.');
           final List<Object?> args = (message as List<Object?>?)!;
@@ -934,9 +1050,12 @@
           codec,
           binaryMessenger: binaryMessenger);
       if (api == null) {
-        channel.setMockMessageHandler(null);
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel, null);
       } else {
-        channel.setMockMessageHandler((Object? message) async {
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel,
+                (Object? message) async {
           assert(message != null,
               'Argument for dev.flutter.pigeon.WebSettingsHostApi.setLoadWithOverviewMode was null.');
           final List<Object?> args = (message as List<Object?>?)!;
@@ -956,9 +1075,12 @@
           'dev.flutter.pigeon.WebSettingsHostApi.setUseWideViewPort', codec,
           binaryMessenger: binaryMessenger);
       if (api == null) {
-        channel.setMockMessageHandler(null);
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel, null);
       } else {
-        channel.setMockMessageHandler((Object? message) async {
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel,
+                (Object? message) async {
           assert(message != null,
               'Argument for dev.flutter.pigeon.WebSettingsHostApi.setUseWideViewPort was null.');
           final List<Object?> args = (message as List<Object?>?)!;
@@ -978,9 +1100,12 @@
           'dev.flutter.pigeon.WebSettingsHostApi.setDisplayZoomControls', codec,
           binaryMessenger: binaryMessenger);
       if (api == null) {
-        channel.setMockMessageHandler(null);
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel, null);
       } else {
-        channel.setMockMessageHandler((Object? message) async {
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel,
+                (Object? message) async {
           assert(message != null,
               'Argument for dev.flutter.pigeon.WebSettingsHostApi.setDisplayZoomControls was null.');
           final List<Object?> args = (message as List<Object?>?)!;
@@ -1000,9 +1125,12 @@
           'dev.flutter.pigeon.WebSettingsHostApi.setBuiltInZoomControls', codec,
           binaryMessenger: binaryMessenger);
       if (api == null) {
-        channel.setMockMessageHandler(null);
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel, null);
       } else {
-        channel.setMockMessageHandler((Object? message) async {
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel,
+                (Object? message) async {
           assert(message != null,
               'Argument for dev.flutter.pigeon.WebSettingsHostApi.setBuiltInZoomControls was null.');
           final List<Object?> args = (message as List<Object?>?)!;
@@ -1022,9 +1150,12 @@
           'dev.flutter.pigeon.WebSettingsHostApi.setAllowFileAccess', codec,
           binaryMessenger: binaryMessenger);
       if (api == null) {
-        channel.setMockMessageHandler(null);
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel, null);
       } else {
-        channel.setMockMessageHandler((Object? message) async {
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel,
+                (Object? message) async {
           assert(message != null,
               'Argument for dev.flutter.pigeon.WebSettingsHostApi.setAllowFileAccess was null.');
           final List<Object?> args = (message as List<Object?>?)!;
@@ -1044,9 +1175,12 @@
           'dev.flutter.pigeon.WebSettingsHostApi.setTextZoom', codec,
           binaryMessenger: binaryMessenger);
       if (api == null) {
-        channel.setMockMessageHandler(null);
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel, null);
       } else {
-        channel.setMockMessageHandler((Object? message) async {
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel,
+                (Object? message) async {
           assert(message != null,
               'Argument for dev.flutter.pigeon.WebSettingsHostApi.setTextZoom was null.');
           final List<Object?> args = (message as List<Object?>?)!;
@@ -1065,6 +1199,8 @@
 }
 
 abstract class TestJavaScriptChannelHostApi {
+  static TestDefaultBinaryMessengerBinding? get _testBinaryMessengerBinding =>
+      TestDefaultBinaryMessengerBinding.instance;
   static const MessageCodec<Object?> codec = StandardMessageCodec();
 
   void create(int instanceId, String channelName);
@@ -1076,9 +1212,12 @@
           'dev.flutter.pigeon.JavaScriptChannelHostApi.create', codec,
           binaryMessenger: binaryMessenger);
       if (api == null) {
-        channel.setMockMessageHandler(null);
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel, null);
       } else {
-        channel.setMockMessageHandler((Object? message) async {
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel,
+                (Object? message) async {
           assert(message != null,
               'Argument for dev.flutter.pigeon.JavaScriptChannelHostApi.create was null.');
           final List<Object?> args = (message as List<Object?>?)!;
@@ -1097,6 +1236,8 @@
 }
 
 abstract class TestWebViewClientHostApi {
+  static TestDefaultBinaryMessengerBinding? get _testBinaryMessengerBinding =>
+      TestDefaultBinaryMessengerBinding.instance;
   static const MessageCodec<Object?> codec = StandardMessageCodec();
 
   void create(int instanceId);
@@ -1111,9 +1252,12 @@
           'dev.flutter.pigeon.WebViewClientHostApi.create', codec,
           binaryMessenger: binaryMessenger);
       if (api == null) {
-        channel.setMockMessageHandler(null);
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel, null);
       } else {
-        channel.setMockMessageHandler((Object? message) async {
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel,
+                (Object? message) async {
           assert(message != null,
               'Argument for dev.flutter.pigeon.WebViewClientHostApi.create was null.');
           final List<Object?> args = (message as List<Object?>?)!;
@@ -1131,9 +1275,12 @@
           codec,
           binaryMessenger: binaryMessenger);
       if (api == null) {
-        channel.setMockMessageHandler(null);
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel, null);
       } else {
-        channel.setMockMessageHandler((Object? message) async {
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel,
+                (Object? message) async {
           assert(message != null,
               'Argument for dev.flutter.pigeon.WebViewClientHostApi.setSynchronousReturnValueForShouldOverrideUrlLoading was null.');
           final List<Object?> args = (message as List<Object?>?)!;
@@ -1153,6 +1300,8 @@
 }
 
 abstract class TestDownloadListenerHostApi {
+  static TestDefaultBinaryMessengerBinding? get _testBinaryMessengerBinding =>
+      TestDefaultBinaryMessengerBinding.instance;
   static const MessageCodec<Object?> codec = StandardMessageCodec();
 
   void create(int instanceId);
@@ -1164,9 +1313,12 @@
           'dev.flutter.pigeon.DownloadListenerHostApi.create', codec,
           binaryMessenger: binaryMessenger);
       if (api == null) {
-        channel.setMockMessageHandler(null);
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel, null);
       } else {
-        channel.setMockMessageHandler((Object? message) async {
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel,
+                (Object? message) async {
           assert(message != null,
               'Argument for dev.flutter.pigeon.DownloadListenerHostApi.create was null.');
           final List<Object?> args = (message as List<Object?>?)!;
@@ -1182,6 +1334,8 @@
 }
 
 abstract class TestWebChromeClientHostApi {
+  static TestDefaultBinaryMessengerBinding? get _testBinaryMessengerBinding =>
+      TestDefaultBinaryMessengerBinding.instance;
   static const MessageCodec<Object?> codec = StandardMessageCodec();
 
   void create(int instanceId);
@@ -1196,9 +1350,12 @@
           'dev.flutter.pigeon.WebChromeClientHostApi.create', codec,
           binaryMessenger: binaryMessenger);
       if (api == null) {
-        channel.setMockMessageHandler(null);
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel, null);
       } else {
-        channel.setMockMessageHandler((Object? message) async {
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel,
+                (Object? message) async {
           assert(message != null,
               'Argument for dev.flutter.pigeon.WebChromeClientHostApi.create was null.');
           final List<Object?> args = (message as List<Object?>?)!;
@@ -1216,9 +1373,12 @@
           codec,
           binaryMessenger: binaryMessenger);
       if (api == null) {
-        channel.setMockMessageHandler(null);
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel, null);
       } else {
-        channel.setMockMessageHandler((Object? message) async {
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel,
+                (Object? message) async {
           assert(message != null,
               'Argument for dev.flutter.pigeon.WebChromeClientHostApi.setSynchronousReturnValueForOnShowFileChooser was null.');
           final List<Object?> args = (message as List<Object?>?)!;
@@ -1238,6 +1398,8 @@
 }
 
 abstract class TestAssetManagerHostApi {
+  static TestDefaultBinaryMessengerBinding? get _testBinaryMessengerBinding =>
+      TestDefaultBinaryMessengerBinding.instance;
   static const MessageCodec<Object?> codec = StandardMessageCodec();
 
   List<String?> list(String path);
@@ -1251,9 +1413,12 @@
           'dev.flutter.pigeon.FlutterAssetManagerHostApi.list', codec,
           binaryMessenger: binaryMessenger);
       if (api == null) {
-        channel.setMockMessageHandler(null);
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel, null);
       } else {
-        channel.setMockMessageHandler((Object? message) async {
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel,
+                (Object? message) async {
           assert(message != null,
               'Argument for dev.flutter.pigeon.FlutterAssetManagerHostApi.list was null.');
           final List<Object?> args = (message as List<Object?>?)!;
@@ -1271,9 +1436,12 @@
           codec,
           binaryMessenger: binaryMessenger);
       if (api == null) {
-        channel.setMockMessageHandler(null);
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel, null);
       } else {
-        channel.setMockMessageHandler((Object? message) async {
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel,
+                (Object? message) async {
           assert(message != null,
               'Argument for dev.flutter.pigeon.FlutterAssetManagerHostApi.getAssetFilePathByName was null.');
           final List<Object?> args = (message as List<Object?>?)!;
@@ -1289,6 +1457,8 @@
 }
 
 abstract class TestWebStorageHostApi {
+  static TestDefaultBinaryMessengerBinding? get _testBinaryMessengerBinding =>
+      TestDefaultBinaryMessengerBinding.instance;
   static const MessageCodec<Object?> codec = StandardMessageCodec();
 
   void create(int instanceId);
@@ -1302,9 +1472,12 @@
           'dev.flutter.pigeon.WebStorageHostApi.create', codec,
           binaryMessenger: binaryMessenger);
       if (api == null) {
-        channel.setMockMessageHandler(null);
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel, null);
       } else {
-        channel.setMockMessageHandler((Object? message) async {
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel,
+                (Object? message) async {
           assert(message != null,
               'Argument for dev.flutter.pigeon.WebStorageHostApi.create was null.');
           final List<Object?> args = (message as List<Object?>?)!;
@@ -1321,9 +1494,12 @@
           'dev.flutter.pigeon.WebStorageHostApi.deleteAllData', codec,
           binaryMessenger: binaryMessenger);
       if (api == null) {
-        channel.setMockMessageHandler(null);
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel, null);
       } else {
-        channel.setMockMessageHandler((Object? message) async {
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel,
+                (Object? message) async {
           assert(message != null,
               'Argument for dev.flutter.pigeon.WebStorageHostApi.deleteAllData was null.');
           final List<Object?> args = (message as List<Object?>?)!;
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/CHANGELOG.md b/packages/webview_flutter/webview_flutter_wkwebview/CHANGELOG.md
index bfce209..dc83b54 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/CHANGELOG.md
+++ b/packages/webview_flutter/webview_flutter_wkwebview/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 3.3.0
+
+* Adds support for `PlatformNavigationDelegate.onUrlChange`.
+
 ## 3.2.4
 
 * Updates pigeon to fix warnings with clang 15.
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 b51d7d8..42b5555 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
@@ -1002,6 +1002,81 @@
       final String? currentUrl = await controller.currentUrl();
       expect(currentUrl, secondaryUrl);
     });
+
+    testWidgets('can receive url changes', (WidgetTester tester) async {
+      final Completer<void> pageLoaded = Completer<void>();
+
+      final PlatformNavigationDelegate navigationDelegate =
+          PlatformNavigationDelegate(
+        const PlatformNavigationDelegateCreationParams(),
+      )..setOnPageFinished((_) => pageLoaded.complete());
+
+      final PlatformWebViewController controller = PlatformWebViewController(
+        const PlatformWebViewControllerCreationParams(),
+      )
+        ..setJavaScriptMode(JavaScriptMode.unrestricted)
+        ..setPlatformNavigationDelegate(navigationDelegate)
+        ..loadRequest(LoadRequestParams(uri: Uri.parse(blankPageEncoded)));
+
+      await tester.pumpWidget(Builder(
+        builder: (BuildContext context) {
+          return PlatformWebViewWidget(
+            PlatformWebViewWidgetCreationParams(controller: controller),
+          ).build(context);
+        },
+      ));
+
+      await pageLoaded.future;
+      await navigationDelegate.setOnPageFinished((_) {});
+
+      final Completer<String> urlChangeCompleter = Completer<String>();
+      await navigationDelegate.setOnUrlChange((UrlChange change) {
+        urlChangeCompleter.complete(change.url);
+      });
+
+      await controller.runJavaScript('location.href = "$primaryUrl"');
+
+      await expectLater(urlChangeCompleter.future, completion(primaryUrl));
+    });
+
+    testWidgets('can receive updates to history state',
+        (WidgetTester tester) async {
+      final Completer<void> pageLoaded = Completer<void>();
+
+      final PlatformNavigationDelegate navigationDelegate =
+          PlatformNavigationDelegate(
+        const PlatformNavigationDelegateCreationParams(),
+      )..setOnPageFinished((_) => pageLoaded.complete());
+
+      final PlatformWebViewController controller = PlatformWebViewController(
+        const PlatformWebViewControllerCreationParams(),
+      )
+        ..setJavaScriptMode(JavaScriptMode.unrestricted)
+        ..setPlatformNavigationDelegate(navigationDelegate)
+        ..loadRequest(LoadRequestParams(uri: Uri.parse(primaryUrl)));
+
+      await tester.pumpWidget(Builder(
+        builder: (BuildContext context) {
+          return PlatformWebViewWidget(
+            PlatformWebViewWidgetCreationParams(controller: controller),
+          ).build(context);
+        },
+      ));
+
+      await pageLoaded.future;
+      await navigationDelegate.setOnPageFinished((_) {});
+
+      final Completer<String> urlChangeCompleter = Completer<String>();
+      await navigationDelegate.setOnUrlChange((UrlChange change) {
+        urlChangeCompleter.complete(change.url);
+      });
+
+      await controller.runJavaScript(
+        'window.history.pushState({}, "", "secondary.txt");',
+      );
+
+      await expectLater(urlChangeCompleter.future, completion(secondaryUrl));
+    });
   });
 
   testWidgets('launches with gestureNavigationEnabled on iOS',
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/example/ios/Runner.xcodeproj/project.pbxproj b/packages/webview_flutter/webview_flutter_wkwebview/example/ios/Runner.xcodeproj/project.pbxproj
index 9e1038d..19e2b39 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/example/ios/Runner.xcodeproj/project.pbxproj
+++ b/packages/webview_flutter/webview_flutter_wkwebview/example/ios/Runner.xcodeproj/project.pbxproj
@@ -10,6 +10,7 @@
 		1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
 		3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
 		8F4FF949299ADC2D000A6586 /* FWFWebViewFlutterWKWebViewExternalAPITests.m in Sources */ = {isa = PBXBuildFile; fileRef = 8F4FF948299ADC2D000A6586 /* FWFWebViewFlutterWKWebViewExternalAPITests.m */; };
+		8F4FF94B29AC223F000A6586 /* FWFURLTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 8F4FF94A29AC223F000A6586 /* FWFURLTests.m */; };
 		8FA6A87928062CD000A4B183 /* FWFInstanceManagerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 8FA6A87828062CD000A4B183 /* FWFInstanceManagerTests.m */; };
 		8FB79B5328134C3100C101D3 /* FWFWebViewHostApiTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 8FB79B5228134C3100C101D3 /* FWFWebViewHostApiTests.m */; };
 		8FB79B55281B24F600C101D3 /* FWFDataConvertersTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 8FB79B54281B24F600C101D3 /* FWFDataConvertersTests.m */; };
@@ -78,6 +79,7 @@
 		7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
 		7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
 		8F4FF948299ADC2D000A6586 /* FWFWebViewFlutterWKWebViewExternalAPITests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FWFWebViewFlutterWKWebViewExternalAPITests.m; sourceTree = "<group>"; };
+		8F4FF94A29AC223F000A6586 /* FWFURLTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FWFURLTests.m; sourceTree = "<group>"; };
 		8FA6A87828062CD000A4B183 /* FWFInstanceManagerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FWFInstanceManagerTests.m; sourceTree = "<group>"; };
 		8FB79B5228134C3100C101D3 /* FWFWebViewHostApiTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FWFWebViewHostApiTests.m; sourceTree = "<group>"; };
 		8FB79B54281B24F600C101D3 /* FWFDataConvertersTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FWFDataConvertersTests.m; sourceTree = "<group>"; };
@@ -162,6 +164,7 @@
 				8FB79B8E2820BAB300C101D3 /* FWFScrollViewHostApiTests.m */,
 				8FB79B902820BAC700C101D3 /* FWFUIViewHostApiTests.m */,
 				8FB79B962821985200C101D3 /* FWFObjectHostApiTests.m */,
+				8F4FF94A29AC223F000A6586 /* FWFURLTests.m */,
 			);
 			path = RunnerTests;
 			sourceTree = "<group>";
@@ -463,6 +466,7 @@
 			buildActionMask = 2147483647;
 			files = (
 				8FA6A87928062CD000A4B183 /* FWFInstanceManagerTests.m in Sources */,
+				8F4FF94B29AC223F000A6586 /* FWFURLTests.m in Sources */,
 				8FB79B852820A3A400C101D3 /* FWFUIDelegateHostApiTests.m in Sources */,
 				8FB79B972821985200C101D3 /* FWFObjectHostApiTests.m in Sources */,
 				8FB79B672820453400C101D3 /* FWFHTTPCookieStoreHostApiTests.m in Sources */,
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/example/ios/RunnerTests/FWFObjectHostApiTests.m b/packages/webview_flutter/webview_flutter_wkwebview/example/ios/RunnerTests/FWFObjectHostApiTests.m
index b8e41d1..888a3a1 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/example/ios/RunnerTests/FWFObjectHostApiTests.m
+++ b/packages/webview_flutter/webview_flutter_wkwebview/example/ios/RunnerTests/FWFObjectHostApiTests.m
@@ -139,7 +139,43 @@
                                  return value[0].value == FWFNSKeyValueChangeKeyEnumOldValue;
                                }]
                              changeValues:[OCMArg checkWithBlock:^BOOL(id value) {
-                               return [@"key" isEqual:value[0]];
+                               FWFObjectOrIdentifier *object = (FWFObjectOrIdentifier *)value[0];
+                               return !object.isIdentifier.boolValue &&
+                                      [@"key" isEqual:object.value];
+                             }]
+                               completion:OCMOCK_ANY]);
+}
+
+- (void)testObserveValueForKeyPathWithIdentifier {
+  FWFInstanceManager *instanceManager = [[FWFInstanceManager alloc] init];
+
+  FWFObject *mockObject = [self mockObjectWithManager:instanceManager identifier:0];
+  FWFObjectFlutterApiImpl *mockFlutterAPI = [self mockFlutterApiWithManager:instanceManager];
+
+  OCMStub([mockObject objectApi]).andReturn(mockFlutterAPI);
+
+  NSObject *object = [[NSObject alloc] init];
+  [instanceManager addDartCreatedInstance:object withIdentifier:1];
+
+  NSObject *returnedObject = [[NSObject alloc] init];
+  [instanceManager addDartCreatedInstance:returnedObject withIdentifier:2];
+
+  [mockObject observeValueForKeyPath:@"keyPath"
+                            ofObject:object
+                              change:@{NSKeyValueChangeOldKey : returnedObject}
+                             context:nil];
+  OCMVerify([mockFlutterAPI
+      observeValueForObjectWithIdentifier:@0
+                                  keyPath:@"keyPath"
+                         objectIdentifier:@1
+                               changeKeys:[OCMArg checkWithBlock:^BOOL(
+                                                      NSArray<FWFNSKeyValueChangeKeyEnumData *>
+                                                          *value) {
+                                 return value[0].value == FWFNSKeyValueChangeKeyEnumOldValue;
+                               }]
+                             changeValues:[OCMArg checkWithBlock:^BOOL(id value) {
+                               FWFObjectOrIdentifier *object = (FWFObjectOrIdentifier *)value[0];
+                               return object.isIdentifier.boolValue && [@(2) isEqual:object.value];
                              }]
                                completion:OCMOCK_ANY]);
 }
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/example/ios/RunnerTests/FWFURLTests.m b/packages/webview_flutter/webview_flutter_wkwebview/example/ios/RunnerTests/FWFURLTests.m
new file mode 100644
index 0000000..bf4dc36
--- /dev/null
+++ b/packages/webview_flutter/webview_flutter_wkwebview/example/ios/RunnerTests/FWFURLTests.m
@@ -0,0 +1,48 @@
+// 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 Flutter;
+@import XCTest;
+@import webview_flutter_wkwebview;
+
+#import <OCMock/OCMock.h>
+
+@interface FWFURLTests : XCTestCase
+@end
+
+@implementation FWFURLTests
+- (void)testAbsoluteString {
+  NSURL *mockUrl = OCMClassMock([NSURL class]);
+  OCMStub([mockUrl absoluteString]).andReturn(@"https://www.google.com");
+
+  FWFInstanceManager *instanceManager = [[FWFInstanceManager alloc] init];
+  [instanceManager addDartCreatedInstance:mockUrl withIdentifier:0];
+
+  FWFURLHostApiImpl *hostApi = [[FWFURLHostApiImpl alloc]
+      initWithBinaryMessenger:OCMProtocolMock(@protocol(FlutterBinaryMessenger))
+              instanceManager:instanceManager];
+
+  FlutterError *error;
+  XCTAssertEqualObjects([hostApi absoluteStringForNSURLWithIdentifier:@(0) error:&error],
+                        @"https://www.google.com");
+  XCTAssertNil(error);
+}
+
+- (void)testFlutterApiCreate {
+  FWFInstanceManager *instanceManager = [[FWFInstanceManager alloc] init];
+  FWFURLFlutterApiImpl *flutterApi = [[FWFURLFlutterApiImpl alloc]
+      initWithBinaryMessenger:OCMProtocolMock(@protocol(FlutterBinaryMessenger))
+              instanceManager:instanceManager];
+
+  flutterApi.api = OCMClassMock([FWFNSUrlFlutterApi class]);
+
+  NSURL *url = [[NSURL alloc] initWithString:@"https://www.google.com"];
+  [flutterApi create:url
+          completion:^(FlutterError *error){
+          }];
+
+  long identifier = [instanceManager identifierWithStrongReferenceForInstance:url];
+  OCMVerify([flutterApi.api createWithIdentifier:@(identifier) completion:OCMOCK_ANY]);
+}
+@end
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/example/lib/main.dart b/packages/webview_flutter/webview_flutter_wkwebview/example/lib/main.dart
index 6489475..a793c2c 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/example/lib/main.dart
+++ b/packages/webview_flutter/webview_flutter_wkwebview/example/lib/main.dart
@@ -124,6 +124,9 @@
             }
             debugPrint('allowing navigation to ${request.url}');
             return NavigationDecision.navigate;
+          })
+          ..setOnUrlChange((UrlChange change) {
+            debugPrint('url change to ${change.url}');
           }),
       )
       ..addJavaScriptChannel(JavaScriptChannelParams(
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/example/pubspec.yaml b/packages/webview_flutter/webview_flutter_wkwebview/example/pubspec.yaml
index 4af215c..b1ee082 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/example/pubspec.yaml
+++ b/packages/webview_flutter/webview_flutter_wkwebview/example/pubspec.yaml
@@ -10,7 +10,7 @@
   flutter:
     sdk: flutter
   path_provider: ^2.0.6
-  webview_flutter_platform_interface: ^2.0.0
+  webview_flutter_platform_interface: ^2.1.0
   webview_flutter_wkwebview:
     # When depending on this package from a real application you should use:
     #   webview_flutter: ^x.y.z
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FLTWebViewFlutterPlugin.m b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FLTWebViewFlutterPlugin.m
index 6233a4e..2f91983 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FLTWebViewFlutterPlugin.m
+++ b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FLTWebViewFlutterPlugin.m
@@ -13,6 +13,7 @@
 #import "FWFScrollViewHostApi.h"
 #import "FWFUIDelegateHostApi.h"
 #import "FWFUIViewHostApi.h"
+#import "FWFURLHostApi.h"
 #import "FWFUserContentControllerHostApi.h"
 #import "FWFWebViewConfigurationHostApi.h"
 #import "FWFWebViewHostApi.h"
@@ -100,6 +101,9 @@
   FWFWKWebViewHostApiSetup(registrar.messenger, [[FWFWebViewHostApiImpl alloc]
                                                     initWithBinaryMessenger:registrar.messenger
                                                             instanceManager:instanceManager]);
+  FWFNSUrlHostApiSetup(registrar.messenger,
+                       [[FWFURLHostApiImpl alloc] initWithBinaryMessenger:registrar.messenger
+                                                          instanceManager:instanceManager]);
 
   FWFWebViewFactory *webviewFactory = [[FWFWebViewFactory alloc] initWithManager:instanceManager];
   [registrar registerViewFactory:webviewFactory withId:@"plugins.flutter.io/webview"];
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFGeneratedWebKitApis.h b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFGeneratedWebKitApis.h
index 0ebb402..1eb95ff 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFGeneratedWebKitApis.h
+++ b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFGeneratedWebKitApis.h
@@ -159,6 +159,7 @@
 @class FWFNSErrorData;
 @class FWFWKScriptMessageData;
 @class FWFNSHttpCookieData;
+@class FWFObjectOrIdentifier;
 
 @interface FWFNSKeyValueObservingOptionsEnumData : NSObject
 /// `init` unavailable to enforce nonnull fields, see the `make` class method.
@@ -300,6 +301,19 @@
 @property(nonatomic, strong) NSArray<id> *propertyValues;
 @end
 
+/// An object that can represent either a value supported by
+/// `StandardMessageCodec`, a data class in this pigeon file, or an identifier
+/// of an object stored in an `InstanceManager`.
+@interface FWFObjectOrIdentifier : NSObject
+/// `init` unavailable to enforce nonnull fields, see the `make` class method.
+- (instancetype)init NS_UNAVAILABLE;
++ (instancetype)makeWithValue:(id)value isIdentifier:(NSNumber *)isIdentifier;
+@property(nonatomic, strong) id value;
+/// Whether value is an int that is used to retrieve an instance stored in an
+/// `InstanceManager`.
+@property(nonatomic, strong) NSNumber *isIdentifier;
+@end
+
 /// The codec used by FWFWKWebsiteDataStoreHostApi.
 NSObject<FlutterMessageCodec> *FWFWKWebsiteDataStoreHostApiGetCodec(void);
 
@@ -583,7 +597,7 @@
                                     keyPath:(NSString *)keyPath
                            objectIdentifier:(NSNumber *)objectIdentifier
                                  changeKeys:(NSArray<FWFNSKeyValueChangeKeyEnumData *> *)changeKeys
-                               changeValues:(NSArray<id> *)changeValues
+                               changeValues:(NSArray<FWFObjectOrIdentifier *> *)changeValues
                                  completion:(void (^)(FlutterError *_Nullable))completion;
 - (void)disposeObjectWithIdentifier:(NSNumber *)identifier
                          completion:(void (^)(FlutterError *_Nullable))completion;
@@ -702,4 +716,39 @@
 extern void FWFWKHttpCookieStoreHostApiSetup(id<FlutterBinaryMessenger> binaryMessenger,
                                              NSObject<FWFWKHttpCookieStoreHostApi> *_Nullable api);
 
+/// The codec used by FWFNSUrlHostApi.
+NSObject<FlutterMessageCodec> *FWFNSUrlHostApiGetCodec(void);
+
+/// Host API for `NSUrl`.
+///
+/// This class may handle instantiating and adding native object instances that
+/// are attached to a Dart instance or method calls on the associated native
+/// class or an instance of the class.
+///
+/// See https://developer.apple.com/documentation/foundation/nsurl?language=objc.
+@protocol FWFNSUrlHostApi
+- (nullable NSString *)absoluteStringForNSURLWithIdentifier:(NSNumber *)identifier
+                                                      error:
+                                                          (FlutterError *_Nullable *_Nonnull)error;
+@end
+
+extern void FWFNSUrlHostApiSetup(id<FlutterBinaryMessenger> binaryMessenger,
+                                 NSObject<FWFNSUrlHostApi> *_Nullable api);
+
+/// The codec used by FWFNSUrlFlutterApi.
+NSObject<FlutterMessageCodec> *FWFNSUrlFlutterApiGetCodec(void);
+
+/// Flutter API for `NSUrl`.
+///
+/// This class may handle instantiating and adding Dart instances that are
+/// attached to a native instance or receiving callback methods from an
+/// overridden native class.
+///
+/// See https://developer.apple.com/documentation/foundation/nsurl?language=objc.
+@interface FWFNSUrlFlutterApi : NSObject
+- (instancetype)initWithBinaryMessenger:(id<FlutterBinaryMessenger>)binaryMessenger;
+- (void)createWithIdentifier:(NSNumber *)identifier
+                  completion:(void (^)(FlutterError *_Nullable))completion;
+@end
+
 NS_ASSUME_NONNULL_END
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFGeneratedWebKitApis.m b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFGeneratedWebKitApis.m
index 957a4de..610bc02 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFGeneratedWebKitApis.m
+++ b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFGeneratedWebKitApis.m
@@ -108,6 +108,12 @@
 - (NSArray *)toList;
 @end
 
+@interface FWFObjectOrIdentifier ()
++ (FWFObjectOrIdentifier *)fromList:(NSArray *)list;
++ (nullable FWFObjectOrIdentifier *)nullableFromList:(NSArray *)list;
+- (NSArray *)toList;
+@end
+
 @implementation FWFNSKeyValueObservingOptionsEnumData
 + (instancetype)makeWithValue:(FWFNSKeyValueObservingOptionsEnum)value {
   FWFNSKeyValueObservingOptionsEnumData *pigeonResult =
@@ -470,6 +476,31 @@
 }
 @end
 
+@implementation FWFObjectOrIdentifier
++ (instancetype)makeWithValue:(id)value isIdentifier:(NSNumber *)isIdentifier {
+  FWFObjectOrIdentifier *pigeonResult = [[FWFObjectOrIdentifier alloc] init];
+  pigeonResult.value = value;
+  pigeonResult.isIdentifier = isIdentifier;
+  return pigeonResult;
+}
++ (FWFObjectOrIdentifier *)fromList:(NSArray *)list {
+  FWFObjectOrIdentifier *pigeonResult = [[FWFObjectOrIdentifier alloc] init];
+  pigeonResult.value = GetNullableObjectAtIndex(list, 0);
+  pigeonResult.isIdentifier = GetNullableObjectAtIndex(list, 1);
+  NSAssert(pigeonResult.isIdentifier != nil, @"");
+  return pigeonResult;
+}
++ (nullable FWFObjectOrIdentifier *)nullableFromList:(NSArray *)list {
+  return (list) ? [FWFObjectOrIdentifier fromList:list] : nil;
+}
+- (NSArray *)toList {
+  return @[
+    (self.value ?: [NSNull null]),
+    (self.isIdentifier ?: [NSNull null]),
+  ];
+}
+@end
+
 @interface FWFWKWebsiteDataStoreHostApiCodecReader : FlutterStandardReader
 @end
 @implementation FWFWKWebsiteDataStoreHostApiCodecReader
@@ -1680,33 +1711,9 @@
 - (nullable id)readValueOfType:(UInt8)type {
   switch (type) {
     case 128:
-      return [FWFNSErrorData fromList:[self readValue]];
-    case 129:
-      return [FWFNSHttpCookieData fromList:[self readValue]];
-    case 130:
-      return [FWFNSHttpCookiePropertyKeyEnumData fromList:[self readValue]];
-    case 131:
       return [FWFNSKeyValueChangeKeyEnumData fromList:[self readValue]];
-    case 132:
-      return [FWFNSKeyValueObservingOptionsEnumData fromList:[self readValue]];
-    case 133:
-      return [FWFNSUrlRequestData fromList:[self readValue]];
-    case 134:
-      return [FWFWKAudiovisualMediaTypeEnumData fromList:[self readValue]];
-    case 135:
-      return [FWFWKFrameInfoData fromList:[self readValue]];
-    case 136:
-      return [FWFWKNavigationActionData fromList:[self readValue]];
-    case 137:
-      return [FWFWKNavigationActionPolicyEnumData fromList:[self readValue]];
-    case 138:
-      return [FWFWKScriptMessageData fromList:[self readValue]];
-    case 139:
-      return [FWFWKUserScriptData fromList:[self readValue]];
-    case 140:
-      return [FWFWKUserScriptInjectionTimeEnumData fromList:[self readValue]];
-    case 141:
-      return [FWFWKWebsiteDataTypeEnumData fromList:[self readValue]];
+    case 129:
+      return [FWFObjectOrIdentifier fromList:[self readValue]];
     default:
       return [super readValueOfType:type];
   }
@@ -1717,48 +1724,12 @@
 @end
 @implementation FWFNSObjectFlutterApiCodecWriter
 - (void)writeValue:(id)value {
-  if ([value isKindOfClass:[FWFNSErrorData class]]) {
+  if ([value isKindOfClass:[FWFNSKeyValueChangeKeyEnumData class]]) {
     [self writeByte:128];
     [self writeValue:[value toList]];
-  } else if ([value isKindOfClass:[FWFNSHttpCookieData class]]) {
+  } else if ([value isKindOfClass:[FWFObjectOrIdentifier class]]) {
     [self writeByte:129];
     [self writeValue:[value toList]];
-  } else if ([value isKindOfClass:[FWFNSHttpCookiePropertyKeyEnumData class]]) {
-    [self writeByte:130];
-    [self writeValue:[value toList]];
-  } else if ([value isKindOfClass:[FWFNSKeyValueChangeKeyEnumData class]]) {
-    [self writeByte:131];
-    [self writeValue:[value toList]];
-  } else if ([value isKindOfClass:[FWFNSKeyValueObservingOptionsEnumData class]]) {
-    [self writeByte:132];
-    [self writeValue:[value toList]];
-  } else if ([value isKindOfClass:[FWFNSUrlRequestData class]]) {
-    [self writeByte:133];
-    [self writeValue:[value toList]];
-  } else if ([value isKindOfClass:[FWFWKAudiovisualMediaTypeEnumData class]]) {
-    [self writeByte:134];
-    [self writeValue:[value toList]];
-  } else if ([value isKindOfClass:[FWFWKFrameInfoData class]]) {
-    [self writeByte:135];
-    [self writeValue:[value toList]];
-  } else if ([value isKindOfClass:[FWFWKNavigationActionData class]]) {
-    [self writeByte:136];
-    [self writeValue:[value toList]];
-  } else if ([value isKindOfClass:[FWFWKNavigationActionPolicyEnumData class]]) {
-    [self writeByte:137];
-    [self writeValue:[value toList]];
-  } else if ([value isKindOfClass:[FWFWKScriptMessageData class]]) {
-    [self writeByte:138];
-    [self writeValue:[value toList]];
-  } else if ([value isKindOfClass:[FWFWKUserScriptData class]]) {
-    [self writeByte:139];
-    [self writeValue:[value toList]];
-  } else if ([value isKindOfClass:[FWFWKUserScriptInjectionTimeEnumData class]]) {
-    [self writeByte:140];
-    [self writeValue:[value toList]];
-  } else if ([value isKindOfClass:[FWFWKWebsiteDataTypeEnumData class]]) {
-    [self writeByte:141];
-    [self writeValue:[value toList]];
   } else {
     [super writeValue:value];
   }
@@ -1805,7 +1776,7 @@
                            objectIdentifier:(NSNumber *)arg_objectIdentifier
                                  changeKeys:
                                      (NSArray<FWFNSKeyValueChangeKeyEnumData *> *)arg_changeKeys
-                               changeValues:(NSArray<id> *)arg_changeValues
+                               changeValues:(NSArray<FWFObjectOrIdentifier *> *)arg_changeValues
                                  completion:(void (^)(FlutterError *_Nullable))completion {
   FlutterBasicMessageChannel *channel = [FlutterBasicMessageChannel
       messageChannelWithName:@"dev.flutter.pigeon.NSObjectFlutterApi.observeValue"
@@ -1851,20 +1822,22 @@
     case 133:
       return [FWFNSUrlRequestData fromList:[self readValue]];
     case 134:
-      return [FWFWKAudiovisualMediaTypeEnumData fromList:[self readValue]];
+      return [FWFObjectOrIdentifier fromList:[self readValue]];
     case 135:
-      return [FWFWKFrameInfoData fromList:[self readValue]];
+      return [FWFWKAudiovisualMediaTypeEnumData fromList:[self readValue]];
     case 136:
-      return [FWFWKNavigationActionData fromList:[self readValue]];
+      return [FWFWKFrameInfoData fromList:[self readValue]];
     case 137:
-      return [FWFWKNavigationActionPolicyEnumData fromList:[self readValue]];
+      return [FWFWKNavigationActionData fromList:[self readValue]];
     case 138:
-      return [FWFWKScriptMessageData fromList:[self readValue]];
+      return [FWFWKNavigationActionPolicyEnumData fromList:[self readValue]];
     case 139:
-      return [FWFWKUserScriptData fromList:[self readValue]];
+      return [FWFWKScriptMessageData fromList:[self readValue]];
     case 140:
-      return [FWFWKUserScriptInjectionTimeEnumData fromList:[self readValue]];
+      return [FWFWKUserScriptData fromList:[self readValue]];
     case 141:
+      return [FWFWKUserScriptInjectionTimeEnumData fromList:[self readValue]];
+    case 142:
       return [FWFWKWebsiteDataTypeEnumData fromList:[self readValue]];
     default:
       return [super readValueOfType:type];
@@ -1894,30 +1867,33 @@
   } else if ([value isKindOfClass:[FWFNSUrlRequestData class]]) {
     [self writeByte:133];
     [self writeValue:[value toList]];
-  } else if ([value isKindOfClass:[FWFWKAudiovisualMediaTypeEnumData class]]) {
+  } else if ([value isKindOfClass:[FWFObjectOrIdentifier class]]) {
     [self writeByte:134];
     [self writeValue:[value toList]];
-  } else if ([value isKindOfClass:[FWFWKFrameInfoData class]]) {
+  } else if ([value isKindOfClass:[FWFWKAudiovisualMediaTypeEnumData class]]) {
     [self writeByte:135];
     [self writeValue:[value toList]];
-  } else if ([value isKindOfClass:[FWFWKNavigationActionData class]]) {
+  } else if ([value isKindOfClass:[FWFWKFrameInfoData class]]) {
     [self writeByte:136];
     [self writeValue:[value toList]];
-  } else if ([value isKindOfClass:[FWFWKNavigationActionPolicyEnumData class]]) {
+  } else if ([value isKindOfClass:[FWFWKNavigationActionData class]]) {
     [self writeByte:137];
     [self writeValue:[value toList]];
-  } else if ([value isKindOfClass:[FWFWKScriptMessageData class]]) {
+  } else if ([value isKindOfClass:[FWFWKNavigationActionPolicyEnumData class]]) {
     [self writeByte:138];
     [self writeValue:[value toList]];
-  } else if ([value isKindOfClass:[FWFWKUserScriptData class]]) {
+  } else if ([value isKindOfClass:[FWFWKScriptMessageData class]]) {
     [self writeByte:139];
     [self writeValue:[value toList]];
-  } else if ([value isKindOfClass:[FWFWKUserScriptInjectionTimeEnumData class]]) {
+  } else if ([value isKindOfClass:[FWFWKUserScriptData class]]) {
     [self writeByte:140];
     [self writeValue:[value toList]];
-  } else if ([value isKindOfClass:[FWFWKWebsiteDataTypeEnumData class]]) {
+  } else if ([value isKindOfClass:[FWFWKUserScriptInjectionTimeEnumData class]]) {
     [self writeByte:141];
     [self writeValue:[value toList]];
+  } else if ([value isKindOfClass:[FWFWKWebsiteDataTypeEnumData class]]) {
+    [self writeByte:142];
+    [self writeValue:[value toList]];
   } else {
     [super writeValue:value];
   }
@@ -2599,3 +2575,64 @@
     }
   }
 }
+NSObject<FlutterMessageCodec> *FWFNSUrlHostApiGetCodec(void) {
+  static FlutterStandardMessageCodec *sSharedObject = nil;
+  sSharedObject = [FlutterStandardMessageCodec sharedInstance];
+  return sSharedObject;
+}
+
+void FWFNSUrlHostApiSetup(id<FlutterBinaryMessenger> binaryMessenger,
+                          NSObject<FWFNSUrlHostApi> *api) {
+  {
+    FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc]
+           initWithName:@"dev.flutter.pigeon.NSUrlHostApi.getAbsoluteString"
+        binaryMessenger:binaryMessenger
+                  codec:FWFNSUrlHostApiGetCodec()];
+    if (api) {
+      NSCAssert([api respondsToSelector:@selector(absoluteStringForNSURLWithIdentifier:error:)],
+                @"FWFNSUrlHostApi api (%@) doesn't respond to "
+                @"@selector(absoluteStringForNSURLWithIdentifier:error:)",
+                api);
+      [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) {
+        NSArray *args = message;
+        NSNumber *arg_identifier = GetNullableObjectAtIndex(args, 0);
+        FlutterError *error;
+        NSString *output = [api absoluteStringForNSURLWithIdentifier:arg_identifier error:&error];
+        callback(wrapResult(output, error));
+      }];
+    } else {
+      [channel setMessageHandler:nil];
+    }
+  }
+}
+NSObject<FlutterMessageCodec> *FWFNSUrlFlutterApiGetCodec(void) {
+  static FlutterStandardMessageCodec *sSharedObject = nil;
+  sSharedObject = [FlutterStandardMessageCodec sharedInstance];
+  return sSharedObject;
+}
+
+@interface FWFNSUrlFlutterApi ()
+@property(nonatomic, strong) NSObject<FlutterBinaryMessenger> *binaryMessenger;
+@end
+
+@implementation FWFNSUrlFlutterApi
+
+- (instancetype)initWithBinaryMessenger:(NSObject<FlutterBinaryMessenger> *)binaryMessenger {
+  self = [super init];
+  if (self) {
+    _binaryMessenger = binaryMessenger;
+  }
+  return self;
+}
+- (void)createWithIdentifier:(NSNumber *)arg_identifier
+                  completion:(void (^)(FlutterError *_Nullable))completion {
+  FlutterBasicMessageChannel *channel = [FlutterBasicMessageChannel
+      messageChannelWithName:@"dev.flutter.pigeon.NSUrlFlutterApi.create"
+             binaryMessenger:self.binaryMessenger
+                       codec:FWFNSUrlFlutterApiGetCodec()];
+  [channel sendMessage:@[ arg_identifier ?: [NSNull null] ]
+                 reply:^(id reply) {
+                   completion(nil);
+                 }];
+}
+@end
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFObjectHostApi.m b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFObjectHostApi.m
index 7da383c..4b014a7 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFObjectHostApi.m
+++ b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFObjectHostApi.m
@@ -3,9 +3,14 @@
 // found in the LICENSE file.
 
 #import "FWFObjectHostApi.h"
+#import <objc/runtime.h>
 #import "FWFDataConverters.h"
+#import "FWFURLHostApi.h"
 
 @interface FWFObjectFlutterApiImpl ()
+// BinaryMessenger must be weak to prevent a circular reference with the host API it
+// references.
+@property(nonatomic, weak) id<FlutterBinaryMessenger> binaryMessenger;
 // InstanceManager must be weak to prevent a circular reference with the object it stores.
 @property(nonatomic, weak) FWFInstanceManager *instanceManager;
 @end
@@ -15,6 +20,7 @@
                         instanceManager:(FWFInstanceManager *)instanceManager {
   self = [self initWithBinaryMessenger:binaryMessenger];
   if (self) {
+    _binaryMessenger = binaryMessenger;
     _instanceManager = instanceManager;
   }
   return self;
@@ -34,7 +40,25 @@
 
   [change enumerateKeysAndObjectsUsingBlock:^(NSKeyValueChangeKey key, id value, BOOL *stop) {
     [changeKeys addObject:FWFNSKeyValueChangeKeyEnumDataFromNSKeyValueChangeKey(key)];
-    [changeValues addObject:value];
+    BOOL isIdentifier = NO;
+    if ([self.instanceManager containsInstance:value]) {
+      isIdentifier = YES;
+    } else if (object_getClass(value) == [NSURL class]) {
+      FWFURLFlutterApiImpl *flutterApi =
+          [[FWFURLFlutterApiImpl alloc] initWithBinaryMessenger:self.binaryMessenger
+                                                instanceManager:self.instanceManager];
+      [flutterApi create:value
+              completion:^(FlutterError *error) {
+                NSAssert(!error, @"%@", error);
+              }];
+      isIdentifier = YES;
+    }
+
+    id returnValue = isIdentifier
+                         ? @([self.instanceManager identifierWithStrongReferenceForInstance:value])
+                         : value;
+    [changeValues addObject:[FWFObjectOrIdentifier makeWithValue:returnValue
+                                                    isIdentifier:@(isIdentifier)]];
   }];
 
   NSNumber *objectIdentifier =
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFURLHostApi.h b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFURLHostApi.h
new file mode 100644
index 0000000..248f0b7
--- /dev/null
+++ b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFURLHostApi.h
@@ -0,0 +1,42 @@
+// 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 <Flutter/Flutter.h>
+#import <Foundation/Foundation.h>
+#import "FWFGeneratedWebKitApis.h"
+#import "FWFInstanceManager.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ * Host API implementation for `NSURL`.
+ *
+ * This class may handle instantiating and adding native object instances that are attached to a
+ * Dart instance or method calls on the associated native class or an instance of the class.
+ */
+@interface FWFURLHostApiImpl : NSObject <FWFNSUrlHostApi>
+- (instancetype)initWithBinaryMessenger:(id<FlutterBinaryMessenger>)binaryMessenger
+                        instanceManager:(FWFInstanceManager *)instanceManager;
+@end
+
+/**
+ * Flutter API implementation for `NSURL`.
+ *
+ * This class may handle instantiating and adding Dart instances that are attached to a native
+ * instance or sending callback methods from an overridden native class.
+ */
+@interface FWFURLFlutterApiImpl : NSObject
+/**
+ * The Flutter API used to send messages back to Dart.
+ */
+@property FWFNSUrlFlutterApi *api;
+- (instancetype)initWithBinaryMessenger:(id<FlutterBinaryMessenger>)binaryMessenger
+                        instanceManager:(FWFInstanceManager *)instanceManager;
+/**
+ * Sends a message to Dart to create a new Dart instance and add it to the `InstanceManager`.
+ */
+- (void)create:(NSURL *)instance completion:(void (^)(FlutterError *_Nullable))completion;
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFURLHostApi.m b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFURLHostApi.m
new file mode 100644
index 0000000..9f747c2
--- /dev/null
+++ b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFURLHostApi.m
@@ -0,0 +1,74 @@
+// 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 "FWFURLHostApi.h"
+
+@interface FWFURLHostApiImpl ()
+// BinaryMessenger must be weak to prevent a circular reference with the host API it
+// references.
+@property(nonatomic, weak) id<FlutterBinaryMessenger> binaryMessenger;
+// InstanceManager must be weak to prevent a circular reference with the object it stores.
+@property(nonatomic, weak) FWFInstanceManager *instanceManager;
+@end
+
+@interface FWFURLFlutterApiImpl ()
+// InstanceManager must be weak to prevent a circular reference with the object it stores.
+@property(nonatomic, weak) FWFInstanceManager *instanceManager;
+@end
+
+@implementation FWFURLHostApiImpl
+- (instancetype)initWithBinaryMessenger:(id<FlutterBinaryMessenger>)binaryMessenger
+                        instanceManager:(FWFInstanceManager *)instanceManager {
+  self = [self init];
+  if (self) {
+    _binaryMessenger = binaryMessenger;
+    _instanceManager = instanceManager;
+  }
+  return self;
+}
+
+- (nullable NSString *)
+    absoluteStringForNSURLWithIdentifier:(nonnull NSNumber *)identifier
+                                   error:(FlutterError *_Nullable __autoreleasing *_Nonnull)error {
+  NSURL *instance = [self urlForIdentifier:identifier error:error];
+  if (*error) {
+    return nil;
+  }
+
+  return instance.absoluteString;
+}
+
+- (nullable NSURL *)urlForIdentifier:(NSNumber *)identifier
+                               error:(FlutterError *_Nullable __autoreleasing *_Nonnull)error {
+  NSURL *instance = (NSURL *)[self.instanceManager instanceForIdentifier:identifier.longValue];
+
+  if (!instance) {
+    NSString *message =
+        [NSString stringWithFormat:@"InstanceManager does not contain an NSURL with identifier: %@",
+                                   identifier];
+    *error = [FlutterError errorWithCode:NSInternalInconsistencyException
+                                 message:message
+                                 details:nil];
+  }
+
+  return instance;
+}
+@end
+
+@implementation FWFURLFlutterApiImpl
+- (instancetype)initWithBinaryMessenger:(id<FlutterBinaryMessenger>)binaryMessenger
+                        instanceManager:(FWFInstanceManager *)instanceManager {
+  self = [self init];
+  if (self) {
+    _instanceManager = instanceManager;
+    _api = [[FWFNSUrlFlutterApi alloc] initWithBinaryMessenger:binaryMessenger];
+  }
+  return self;
+}
+
+- (void)create:(NSURL *)instance completion:(void (^)(FlutterError *_Nullable))completion {
+  [self.api createWithIdentifier:@([self.instanceManager addHostCreatedInstance:instance])
+                      completion:completion];
+}
+@end
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/webview-umbrella.h b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/webview-umbrella.h
index 9cf4ed2..2836829 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/webview-umbrella.h
+++ b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/webview-umbrella.h
@@ -16,6 +16,7 @@
 #import "FWFScrollViewHostApi.h"
 #import "FWFUIDelegateHostApi.h"
 #import "FWFUIViewHostApi.h"
+#import "FWFURLHostApi.h"
 #import "FWFUserContentControllerHostApi.h"
 #import "FWFWebViewConfigurationHostApi.h"
 #import "FWFWebViewFlutterWKWebViewExternalAPI.h"
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/lib/src/common/web_kit.g.dart b/packages/webview_flutter/webview_flutter_wkwebview/lib/src/common/web_kit.g.dart
index 75d7aab..c44e52a 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/lib/src/common/web_kit.g.dart
+++ b/packages/webview_flutter/webview_flutter_wkwebview/lib/src/common/web_kit.g.dart
@@ -513,6 +513,37 @@
   }
 }
 
+/// An object that can represent either a value supported by
+/// `StandardMessageCodec`, a data class in this pigeon file, or an identifier
+/// of an object stored in an `InstanceManager`.
+class ObjectOrIdentifier {
+  ObjectOrIdentifier({
+    this.value,
+    required this.isIdentifier,
+  });
+
+  Object? value;
+
+  /// Whether value is an int that is used to retrieve an instance stored in an
+  /// `InstanceManager`.
+  bool isIdentifier;
+
+  Object encode() {
+    return <Object?>[
+      value,
+      isIdentifier,
+    ];
+  }
+
+  static ObjectOrIdentifier decode(Object result) {
+    result as List<Object?>;
+    return ObjectOrIdentifier(
+      value: result[0] as Object?,
+      isIdentifier: result[1]! as bool,
+    );
+  }
+}
+
 class _WKWebsiteDataStoreHostApiCodec extends StandardMessageCodec {
   const _WKWebsiteDataStoreHostApiCodec();
   @override
@@ -1699,48 +1730,12 @@
   const _NSObjectFlutterApiCodec();
   @override
   void writeValue(WriteBuffer buffer, Object? value) {
-    if (value is NSErrorData) {
+    if (value is NSKeyValueChangeKeyEnumData) {
       buffer.putUint8(128);
       writeValue(buffer, value.encode());
-    } else if (value is NSHttpCookieData) {
+    } else if (value is ObjectOrIdentifier) {
       buffer.putUint8(129);
       writeValue(buffer, value.encode());
-    } else if (value is NSHttpCookiePropertyKeyEnumData) {
-      buffer.putUint8(130);
-      writeValue(buffer, value.encode());
-    } else if (value is NSKeyValueChangeKeyEnumData) {
-      buffer.putUint8(131);
-      writeValue(buffer, value.encode());
-    } else if (value is NSKeyValueObservingOptionsEnumData) {
-      buffer.putUint8(132);
-      writeValue(buffer, value.encode());
-    } else if (value is NSUrlRequestData) {
-      buffer.putUint8(133);
-      writeValue(buffer, value.encode());
-    } else if (value is WKAudiovisualMediaTypeEnumData) {
-      buffer.putUint8(134);
-      writeValue(buffer, value.encode());
-    } else if (value is WKFrameInfoData) {
-      buffer.putUint8(135);
-      writeValue(buffer, value.encode());
-    } else if (value is WKNavigationActionData) {
-      buffer.putUint8(136);
-      writeValue(buffer, value.encode());
-    } else if (value is WKNavigationActionPolicyEnumData) {
-      buffer.putUint8(137);
-      writeValue(buffer, value.encode());
-    } else if (value is WKScriptMessageData) {
-      buffer.putUint8(138);
-      writeValue(buffer, value.encode());
-    } else if (value is WKUserScriptData) {
-      buffer.putUint8(139);
-      writeValue(buffer, value.encode());
-    } else if (value is WKUserScriptInjectionTimeEnumData) {
-      buffer.putUint8(140);
-      writeValue(buffer, value.encode());
-    } else if (value is WKWebsiteDataTypeEnumData) {
-      buffer.putUint8(141);
-      writeValue(buffer, value.encode());
     } else {
       super.writeValue(buffer, value);
     }
@@ -1750,33 +1745,9 @@
   Object? readValueOfType(int type, ReadBuffer buffer) {
     switch (type) {
       case 128:
-        return NSErrorData.decode(readValue(buffer)!);
-      case 129:
-        return NSHttpCookieData.decode(readValue(buffer)!);
-      case 130:
-        return NSHttpCookiePropertyKeyEnumData.decode(readValue(buffer)!);
-      case 131:
         return NSKeyValueChangeKeyEnumData.decode(readValue(buffer)!);
-      case 132:
-        return NSKeyValueObservingOptionsEnumData.decode(readValue(buffer)!);
-      case 133:
-        return NSUrlRequestData.decode(readValue(buffer)!);
-      case 134:
-        return WKAudiovisualMediaTypeEnumData.decode(readValue(buffer)!);
-      case 135:
-        return WKFrameInfoData.decode(readValue(buffer)!);
-      case 136:
-        return WKNavigationActionData.decode(readValue(buffer)!);
-      case 137:
-        return WKNavigationActionPolicyEnumData.decode(readValue(buffer)!);
-      case 138:
-        return WKScriptMessageData.decode(readValue(buffer)!);
-      case 139:
-        return WKUserScriptData.decode(readValue(buffer)!);
-      case 140:
-        return WKUserScriptInjectionTimeEnumData.decode(readValue(buffer)!);
-      case 141:
-        return WKWebsiteDataTypeEnumData.decode(readValue(buffer)!);
+      case 129:
+        return ObjectOrIdentifier.decode(readValue(buffer)!);
       default:
         return super.readValueOfType(type, buffer);
     }
@@ -1794,7 +1765,7 @@
       String keyPath,
       int objectIdentifier,
       List<NSKeyValueChangeKeyEnumData?> changeKeys,
-      List<Object?> changeValues);
+      List<ObjectOrIdentifier?> changeValues);
 
   void dispose(int identifier);
 
@@ -1824,10 +1795,10 @@
               (args[3] as List<Object?>?)?.cast<NSKeyValueChangeKeyEnumData?>();
           assert(arg_changeKeys != null,
               'Argument for dev.flutter.pigeon.NSObjectFlutterApi.observeValue was null, expected non-null List<NSKeyValueChangeKeyEnumData?>.');
-          final List<Object?>? arg_changeValues =
-              (args[4] as List<Object?>?)?.cast<Object?>();
+          final List<ObjectOrIdentifier?>? arg_changeValues =
+              (args[4] as List<Object?>?)?.cast<ObjectOrIdentifier?>();
           assert(arg_changeValues != null,
-              'Argument for dev.flutter.pigeon.NSObjectFlutterApi.observeValue was null, expected non-null List<Object?>.');
+              'Argument for dev.flutter.pigeon.NSObjectFlutterApi.observeValue was null, expected non-null List<ObjectOrIdentifier?>.');
           api.observeValue(arg_identifier!, arg_keyPath!, arg_objectIdentifier!,
               arg_changeKeys!, arg_changeValues!);
           return;
@@ -1878,30 +1849,33 @@
     } else if (value is NSUrlRequestData) {
       buffer.putUint8(133);
       writeValue(buffer, value.encode());
-    } else if (value is WKAudiovisualMediaTypeEnumData) {
+    } else if (value is ObjectOrIdentifier) {
       buffer.putUint8(134);
       writeValue(buffer, value.encode());
-    } else if (value is WKFrameInfoData) {
+    } else if (value is WKAudiovisualMediaTypeEnumData) {
       buffer.putUint8(135);
       writeValue(buffer, value.encode());
-    } else if (value is WKNavigationActionData) {
+    } else if (value is WKFrameInfoData) {
       buffer.putUint8(136);
       writeValue(buffer, value.encode());
-    } else if (value is WKNavigationActionPolicyEnumData) {
+    } else if (value is WKNavigationActionData) {
       buffer.putUint8(137);
       writeValue(buffer, value.encode());
-    } else if (value is WKScriptMessageData) {
+    } else if (value is WKNavigationActionPolicyEnumData) {
       buffer.putUint8(138);
       writeValue(buffer, value.encode());
-    } else if (value is WKUserScriptData) {
+    } else if (value is WKScriptMessageData) {
       buffer.putUint8(139);
       writeValue(buffer, value.encode());
-    } else if (value is WKUserScriptInjectionTimeEnumData) {
+    } else if (value is WKUserScriptData) {
       buffer.putUint8(140);
       writeValue(buffer, value.encode());
-    } else if (value is WKWebsiteDataTypeEnumData) {
+    } else if (value is WKUserScriptInjectionTimeEnumData) {
       buffer.putUint8(141);
       writeValue(buffer, value.encode());
+    } else if (value is WKWebsiteDataTypeEnumData) {
+      buffer.putUint8(142);
+      writeValue(buffer, value.encode());
     } else {
       super.writeValue(buffer, value);
     }
@@ -1923,20 +1897,22 @@
       case 133:
         return NSUrlRequestData.decode(readValue(buffer)!);
       case 134:
-        return WKAudiovisualMediaTypeEnumData.decode(readValue(buffer)!);
+        return ObjectOrIdentifier.decode(readValue(buffer)!);
       case 135:
-        return WKFrameInfoData.decode(readValue(buffer)!);
+        return WKAudiovisualMediaTypeEnumData.decode(readValue(buffer)!);
       case 136:
-        return WKNavigationActionData.decode(readValue(buffer)!);
+        return WKFrameInfoData.decode(readValue(buffer)!);
       case 137:
-        return WKNavigationActionPolicyEnumData.decode(readValue(buffer)!);
+        return WKNavigationActionData.decode(readValue(buffer)!);
       case 138:
-        return WKScriptMessageData.decode(readValue(buffer)!);
+        return WKNavigationActionPolicyEnumData.decode(readValue(buffer)!);
       case 139:
-        return WKUserScriptData.decode(readValue(buffer)!);
+        return WKScriptMessageData.decode(readValue(buffer)!);
       case 140:
-        return WKUserScriptInjectionTimeEnumData.decode(readValue(buffer)!);
+        return WKUserScriptData.decode(readValue(buffer)!);
       case 141:
+        return WKUserScriptInjectionTimeEnumData.decode(readValue(buffer)!);
+      case 142:
         return WKWebsiteDataTypeEnumData.decode(readValue(buffer)!);
       default:
         return super.readValueOfType(type, buffer);
@@ -2587,3 +2563,78 @@
     }
   }
 }
+
+/// Host API for `NSUrl`.
+///
+/// This class may handle instantiating and adding native object instances that
+/// are attached to a Dart instance or method calls on the associated native
+/// class or an instance of the class.
+///
+/// See https://developer.apple.com/documentation/foundation/nsurl?language=objc.
+class NSUrlHostApi {
+  /// Constructor for [NSUrlHostApi].  The [binaryMessenger] named argument is
+  /// available for dependency injection.  If it is left null, the default
+  /// BinaryMessenger will be used which routes to the host platform.
+  NSUrlHostApi({BinaryMessenger? binaryMessenger})
+      : _binaryMessenger = binaryMessenger;
+  final BinaryMessenger? _binaryMessenger;
+
+  static const MessageCodec<Object?> codec = StandardMessageCodec();
+
+  Future<String?> getAbsoluteString(int arg_identifier) async {
+    final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
+        'dev.flutter.pigeon.NSUrlHostApi.getAbsoluteString', codec,
+        binaryMessenger: _binaryMessenger);
+    final List<Object?>? replyList =
+        await channel.send(<Object?>[arg_identifier]) as List<Object?>?;
+    if (replyList == null) {
+      throw PlatformException(
+        code: 'channel-error',
+        message: 'Unable to establish connection on channel.',
+      );
+    } else if (replyList.length > 1) {
+      throw PlatformException(
+        code: replyList[0]! as String,
+        message: replyList[1] as String?,
+        details: replyList[2],
+      );
+    } else {
+      return (replyList[0] as String?);
+    }
+  }
+}
+
+/// Flutter API for `NSUrl`.
+///
+/// This class may handle instantiating and adding Dart instances that are
+/// attached to a native instance or receiving callback methods from an
+/// overridden native class.
+///
+/// See https://developer.apple.com/documentation/foundation/nsurl?language=objc.
+abstract class NSUrlFlutterApi {
+  static const MessageCodec<Object?> codec = StandardMessageCodec();
+
+  void create(int identifier);
+
+  static void setup(NSUrlFlutterApi? api, {BinaryMessenger? binaryMessenger}) {
+    {
+      final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
+          'dev.flutter.pigeon.NSUrlFlutterApi.create', codec,
+          binaryMessenger: binaryMessenger);
+      if (api == null) {
+        channel.setMessageHandler(null);
+      } else {
+        channel.setMessageHandler((Object? message) async {
+          assert(message != null,
+              'Argument for dev.flutter.pigeon.NSUrlFlutterApi.create was null.');
+          final List<Object?> args = (message as List<Object?>?)!;
+          final int? arg_identifier = (args[0] as int?);
+          assert(arg_identifier != null,
+              'Argument for dev.flutter.pigeon.NSUrlFlutterApi.create was null, expected non-null int.');
+          api.create(arg_identifier!);
+          return;
+        });
+      }
+    }
+  }
+}
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/lib/src/foundation/foundation.dart b/packages/webview_flutter/webview_flutter_wkwebview/lib/src/foundation/foundation.dart
index 4d85c39..a9bbdc5 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/lib/src/foundation/foundation.dart
+++ b/packages/webview_flutter/webview_flutter_wkwebview/lib/src/foundation/foundation.dart
@@ -235,6 +235,42 @@
   final Map<NSHttpCookiePropertyKey, Object> properties;
 }
 
+/// An object that represents the location of a resource, such as an item on a
+/// remote server or the path to a local file.
+///
+/// See https://developer.apple.com/documentation/foundation/nsurl?language=objc.
+class NSUrl extends NSObject {
+  /// Instantiates a [NSUrl] without creating and attaching to an instance
+  /// of the associated native class.
+  ///
+  /// This should only be used outside of tests by subclasses created by this
+  /// library or to create a copy for an [InstanceManager].
+  @protected
+  NSUrl.detached({super.binaryMessenger, super.instanceManager})
+      : _nsUrlHostApi = NSUrlHostApiImpl(
+          binaryMessenger: binaryMessenger,
+          instanceManager: instanceManager,
+        ),
+        super.detached();
+
+  final NSUrlHostApiImpl _nsUrlHostApi;
+
+  /// The URL string for the receiver as an absolute URL. (read-only)
+  ///
+  /// Represents [NSURL.absoluteString](https://developer.apple.com/documentation/foundation/nsurl/1409868-absolutestring?language=objc).
+  Future<String?> getAbsoluteString() {
+    return _nsUrlHostApi.getAbsoluteStringFromInstances(this);
+  }
+
+  @override
+  NSObject copy() {
+    return NSUrl.detached(
+      binaryMessenger: _nsUrlHostApi.binaryMessenger,
+      instanceManager: _nsUrlHostApi.instanceManager,
+    );
+  }
+}
+
 /// The root class of most Objective-C class hierarchies.
 @immutable
 class NSObject with Copyable {
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/lib/src/foundation/foundation_api_impls.dart b/packages/webview_flutter/webview_flutter_wkwebview/lib/src/foundation/foundation_api_impls.dart
index 445e232..4f73c08 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/lib/src/foundation/foundation_api_impls.dart
+++ b/packages/webview_flutter/webview_flutter_wkwebview/lib/src/foundation/foundation_api_impls.dart
@@ -52,7 +52,9 @@
     BinaryMessenger? binaryMessenger,
     InstanceManager? instanceManager,
   })  : _binaryMessenger = binaryMessenger,
-        object = NSObjectFlutterApiImpl(
+        object = NSObjectFlutterApiImpl(instanceManager: instanceManager),
+        url = NSUrlFlutterApiImpl(
+          binaryMessenger: binaryMessenger,
           instanceManager: instanceManager,
         );
 
@@ -76,6 +78,10 @@
   @visibleForTesting
   final NSObjectFlutterApiImpl object;
 
+  /// Flutter Api for [NSUrl].
+  @visibleForTesting
+  final NSUrlFlutterApiImpl url;
+
   /// Ensures all the Flutter APIs have been set up to receive calls from native code.
   void ensureSetUp() {
     if (!_hasBeenSetUp) {
@@ -83,6 +89,7 @@
         object,
         binaryMessenger: _binaryMessenger,
       );
+      NSUrlFlutterApi.setup(url, binaryMessenger: _binaryMessenger);
       _hasBeenSetUp = true;
     }
   }
@@ -154,7 +161,7 @@
     String keyPath,
     int objectIdentifier,
     List<NSKeyValueChangeKeyEnumData?> changeKeys,
-    List<Object?> changeValues,
+    List<ObjectOrIdentifier?> changeValues,
   ) {
     final void Function(String, NSObject, Map<NSKeyValueChangeKey, Object?>)?
         function = _getObject(identifier).observeValue;
@@ -163,11 +170,20 @@
       instanceManager.getInstanceWithWeakReference(objectIdentifier)!
           as NSObject,
       Map<NSKeyValueChangeKey, Object?>.fromIterables(
-          changeKeys.map<NSKeyValueChangeKey>(
-        (NSKeyValueChangeKeyEnumData? data) {
-          return data!.toNSKeyValueChangeKey();
-        },
-      ), changeValues),
+        changeKeys.map<NSKeyValueChangeKey>(
+          (NSKeyValueChangeKeyEnumData? data) {
+            return data!.toNSKeyValueChangeKey();
+          },
+        ),
+        changeValues.map<Object?>((ObjectOrIdentifier? value) {
+          if (value != null && value.isIdentifier) {
+            return instanceManager.getInstanceWithWeakReference(
+              value.value! as int,
+            );
+          }
+          return value?.value;
+        }),
+      ),
     );
   }
 
@@ -176,3 +192,60 @@
     instanceManager.remove(identifier);
   }
 }
+
+/// Host api implementation for [NSUrl].
+class NSUrlHostApiImpl extends NSUrlHostApi {
+  /// Constructs an [NSUrlHostApiImpl].
+  NSUrlHostApiImpl({
+    this.binaryMessenger,
+    InstanceManager? instanceManager,
+  })  : instanceManager = instanceManager ?? NSObject.globalInstanceManager,
+        super(binaryMessenger: binaryMessenger);
+
+  /// Sends binary data across the Flutter platform barrier.
+  ///
+  /// If it is null, the default BinaryMessenger will be used which routes to
+  /// the host platform.
+  final BinaryMessenger? binaryMessenger;
+
+  /// Maintains instances stored to communicate with Objective-C objects.
+  final InstanceManager instanceManager;
+
+  /// Calls [getAbsoluteString] with the ids of the provided object instances.
+  Future<String?> getAbsoluteStringFromInstances(NSUrl instance) {
+    return getAbsoluteString(instanceManager.getIdentifier(instance)!);
+  }
+}
+
+/// Flutter API implementation for [NSUrl].
+///
+/// This class may handle instantiating and adding Dart instances that are
+/// attached to a native instance or receiving callback methods from an
+/// overridden native class.
+class NSUrlFlutterApiImpl implements NSUrlFlutterApi {
+  /// Constructs a [NSUrlFlutterApiImpl].
+  NSUrlFlutterApiImpl({
+    this.binaryMessenger,
+    InstanceManager? instanceManager,
+  }) : instanceManager = instanceManager ?? NSObject.globalInstanceManager;
+
+  /// Receives binary data across the Flutter platform barrier.
+  ///
+  /// If it is null, the default BinaryMessenger will be used which routes to
+  /// the host platform.
+  final BinaryMessenger? binaryMessenger;
+
+  /// Maintains instances stored to communicate with native language objects.
+  final InstanceManager instanceManager;
+
+  @override
+  void create(int identifier) {
+    instanceManager.addHostCreatedInstance(
+      NSUrl.detached(
+        binaryMessenger: binaryMessenger,
+        instanceManager: instanceManager,
+      ),
+      identifier,
+    );
+  }
+}
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 76d4a17..9ca4744 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
@@ -130,6 +130,14 @@
         NSKeyValueObservingOptions.newValue,
       },
     );
+
+    _webView.addObserver(
+      _webView,
+      keyPath: 'URL',
+      options: <NSKeyValueObservingOptions>{
+        NSKeyValueObservingOptions.newValue,
+      },
+    );
   }
 
   /// The WebKit WebView being controlled.
@@ -142,13 +150,30 @@
         String keyPath,
         NSObject object,
         Map<NSKeyValueChangeKey, Object?> change,
-      ) {
-        final ProgressCallback? progressCallback =
-            weakReference.target?._currentNavigationDelegate?._onProgress;
-        if (progressCallback != null) {
-          final double progress =
-              change[NSKeyValueChangeKey.newValue]! as double;
-          progressCallback((progress * 100).round());
+      ) async {
+        final WebKitWebViewController? controller = weakReference.target;
+        if (controller == null) {
+          return;
+        }
+
+        switch (keyPath) {
+          case 'estimatedProgress':
+            final ProgressCallback? progressCallback =
+                controller._currentNavigationDelegate?._onProgress;
+            if (progressCallback != null) {
+              final double progress =
+                  change[NSKeyValueChangeKey.newValue]! as double;
+              progressCallback((progress * 100).round());
+            }
+            break;
+          case 'URL':
+            final UrlChangeCallback? urlChangeCallback =
+                controller._currentNavigationDelegate?._onUrlChange;
+            if (urlChangeCallback != null) {
+              final NSUrl url = change[NSKeyValueChangeKey.newValue]! as NSUrl;
+              urlChangeCallback(UrlChange(url: await url.getAbsoluteString()));
+            }
+            break;
         }
       };
     }),
@@ -691,6 +716,7 @@
   ProgressCallback? _onProgress;
   WebResourceErrorCallback? _onWebResourceError;
   NavigationRequestCallback? _onNavigationRequest;
+  UrlChangeCallback? _onUrlChange;
 
   @override
   Future<void> setOnPageFinished(PageEventCallback onPageFinished) async {
@@ -720,4 +746,9 @@
   ) async {
     _onNavigationRequest = onNavigationRequest;
   }
+
+  @override
+  Future<void> setOnUrlChange(UrlChangeCallback onUrlChange) async {
+    _onUrlChange = onUrlChange;
+  }
 }
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/pigeons/web_kit.dart b/packages/webview_flutter/webview_flutter_wkwebview/pigeons/web_kit.dart
index 7e6c847..8dcbc2a 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/pigeons/web_kit.dart
+++ b/packages/webview_flutter/webview_flutter_wkwebview/pigeons/web_kit.dart
@@ -258,6 +258,17 @@
   late List<Object?> propertyValues;
 }
 
+/// An object that can represent either a value supported by
+/// `StandardMessageCodec`, a data class in this pigeon file, or an identifier
+/// of an object stored in an `InstanceManager`.
+class ObjectOrIdentifier {
+  late Object? value;
+
+  /// Whether value is an int that is used to retrieve an instance stored in an
+  /// `InstanceManager`.
+  late bool isIdentifier;
+}
+
 /// Mirror of WKWebsiteDataStore.
 ///
 /// See https://developer.apple.com/documentation/webkit/wkwebsitedatastore?language=objc.
@@ -536,7 +547,7 @@
     // conform to `NSCopying`. This splits the map of properties into a list of
     // keys and values with the ordered maintained.
     List<NSKeyValueChangeKeyEnumData?> changeKeys,
-    List<Object?> changeValues,
+    List<ObjectOrIdentifier> changeValues,
   );
 
   @ObjCSelector('disposeObjectWithIdentifier:')
@@ -646,3 +657,29 @@
   @async
   void setCookie(int identifier, NSHttpCookieData cookie);
 }
+
+/// Host API for `NSUrl`.
+///
+/// This class may handle instantiating and adding native object instances that
+/// are attached to a Dart instance or method calls on the associated native
+/// class or an instance of the class.
+///
+/// See https://developer.apple.com/documentation/foundation/nsurl?language=objc.
+@HostApi(dartHostTestHandler: 'TestNSUrlHostApi')
+abstract class NSUrlHostApi {
+  @ObjCSelector('absoluteStringForNSURLWithIdentifier:')
+  String? getAbsoluteString(int identifier);
+}
+
+/// Flutter API for `NSUrl`.
+///
+/// This class may handle instantiating and adding Dart instances that are
+/// attached to a native instance or receiving callback methods from an
+/// overridden native class.
+///
+/// See https://developer.apple.com/documentation/foundation/nsurl?language=objc.
+@FlutterApi()
+abstract class NSUrlFlutterApi {
+  @ObjCSelector('createWithIdentifier:')
+  void create(int identifier);
+}
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/pubspec.yaml b/packages/webview_flutter/webview_flutter_wkwebview/pubspec.yaml
index 6d32867..4c5c748 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/packages/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.2.4
+version: 3.3.0
 
 environment:
   sdk: ">=2.18.0 <4.0.0"
@@ -20,7 +20,7 @@
   flutter:
     sdk: flutter
   path: ^1.8.0
-  webview_flutter_platform_interface: ^2.0.0
+  webview_flutter_platform_interface: ^2.1.0
 
 dev_dependencies:
   build_runner: ^2.1.5
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/test/src/common/test_web_kit.g.dart b/packages/webview_flutter/webview_flutter_wkwebview/test/src/common/test_web_kit.g.dart
index ce6ecb6..a9b27a0 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/test/src/common/test_web_kit.g.dart
+++ b/packages/webview_flutter/webview_flutter_wkwebview/test/src/common/test_web_kit.g.dart
@@ -986,30 +986,33 @@
     } else if (value is NSUrlRequestData) {
       buffer.putUint8(133);
       writeValue(buffer, value.encode());
-    } else if (value is WKAudiovisualMediaTypeEnumData) {
+    } else if (value is ObjectOrIdentifier) {
       buffer.putUint8(134);
       writeValue(buffer, value.encode());
-    } else if (value is WKFrameInfoData) {
+    } else if (value is WKAudiovisualMediaTypeEnumData) {
       buffer.putUint8(135);
       writeValue(buffer, value.encode());
-    } else if (value is WKNavigationActionData) {
+    } else if (value is WKFrameInfoData) {
       buffer.putUint8(136);
       writeValue(buffer, value.encode());
-    } else if (value is WKNavigationActionPolicyEnumData) {
+    } else if (value is WKNavigationActionData) {
       buffer.putUint8(137);
       writeValue(buffer, value.encode());
-    } else if (value is WKScriptMessageData) {
+    } else if (value is WKNavigationActionPolicyEnumData) {
       buffer.putUint8(138);
       writeValue(buffer, value.encode());
-    } else if (value is WKUserScriptData) {
+    } else if (value is WKScriptMessageData) {
       buffer.putUint8(139);
       writeValue(buffer, value.encode());
-    } else if (value is WKUserScriptInjectionTimeEnumData) {
+    } else if (value is WKUserScriptData) {
       buffer.putUint8(140);
       writeValue(buffer, value.encode());
-    } else if (value is WKWebsiteDataTypeEnumData) {
+    } else if (value is WKUserScriptInjectionTimeEnumData) {
       buffer.putUint8(141);
       writeValue(buffer, value.encode());
+    } else if (value is WKWebsiteDataTypeEnumData) {
+      buffer.putUint8(142);
+      writeValue(buffer, value.encode());
     } else {
       super.writeValue(buffer, value);
     }
@@ -1031,20 +1034,22 @@
       case 133:
         return NSUrlRequestData.decode(readValue(buffer)!);
       case 134:
-        return WKAudiovisualMediaTypeEnumData.decode(readValue(buffer)!);
+        return ObjectOrIdentifier.decode(readValue(buffer)!);
       case 135:
-        return WKFrameInfoData.decode(readValue(buffer)!);
+        return WKAudiovisualMediaTypeEnumData.decode(readValue(buffer)!);
       case 136:
-        return WKNavigationActionData.decode(readValue(buffer)!);
+        return WKFrameInfoData.decode(readValue(buffer)!);
       case 137:
-        return WKNavigationActionPolicyEnumData.decode(readValue(buffer)!);
+        return WKNavigationActionData.decode(readValue(buffer)!);
       case 138:
-        return WKScriptMessageData.decode(readValue(buffer)!);
+        return WKNavigationActionPolicyEnumData.decode(readValue(buffer)!);
       case 139:
-        return WKUserScriptData.decode(readValue(buffer)!);
+        return WKScriptMessageData.decode(readValue(buffer)!);
       case 140:
-        return WKUserScriptInjectionTimeEnumData.decode(readValue(buffer)!);
+        return WKUserScriptData.decode(readValue(buffer)!);
       case 141:
+        return WKUserScriptInjectionTimeEnumData.decode(readValue(buffer)!);
+      case 142:
         return WKWebsiteDataTypeEnumData.decode(readValue(buffer)!);
       default:
         return super.readValueOfType(type, buffer);
@@ -1664,3 +1669,43 @@
     }
   }
 }
+
+/// Host API for `NSUrl`.
+///
+/// This class may handle instantiating and adding native object instances that
+/// are attached to a Dart instance or method calls on the associated native
+/// class or an instance of the class.
+///
+/// See https://developer.apple.com/documentation/foundation/nsurl?language=objc.
+abstract class TestNSUrlHostApi {
+  static TestDefaultBinaryMessengerBinding? get _testBinaryMessengerBinding =>
+      TestDefaultBinaryMessengerBinding.instance;
+  static const MessageCodec<Object?> codec = StandardMessageCodec();
+
+  String? getAbsoluteString(int identifier);
+
+  static void setup(TestNSUrlHostApi? api, {BinaryMessenger? binaryMessenger}) {
+    {
+      final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
+          'dev.flutter.pigeon.NSUrlHostApi.getAbsoluteString', codec,
+          binaryMessenger: binaryMessenger);
+      if (api == null) {
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel, null);
+      } else {
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel,
+                (Object? message) async {
+          assert(message != null,
+              'Argument for dev.flutter.pigeon.NSUrlHostApi.getAbsoluteString was null.');
+          final List<Object?> args = (message as List<Object?>?)!;
+          final int? arg_identifier = (args[0] as int?);
+          assert(arg_identifier != null,
+              'Argument for dev.flutter.pigeon.NSUrlHostApi.getAbsoluteString was null, expected non-null int.');
+          final String? output = api.getAbsoluteString(arg_identifier!);
+          return <Object?>[output];
+        });
+      }
+    }
+  }
+}
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/test/src/foundation/foundation_test.dart b/packages/webview_flutter/webview_flutter_wkwebview/test/src/foundation/foundation_test.dart
index b953620..a6e0427 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/test/src/foundation/foundation_test.dart
+++ b/packages/webview_flutter/webview_flutter_wkwebview/test/src/foundation/foundation_test.dart
@@ -17,6 +17,7 @@
 
 @GenerateMocks(<Type>[
   TestNSObjectHostApi,
+  TestNSUrlHostApi,
 ])
 void main() {
   TestWidgetsFlutterBinding.ensureInitialized();
@@ -137,7 +138,9 @@
           <NSKeyValueChangeKeyEnumData>[
             NSKeyValueChangeKeyEnumData(value: NSKeyValueChangeKeyEnum.oldValue)
           ],
-          <Object?>['value'],
+          <ObjectOrIdentifier?>[
+            ObjectOrIdentifier(isIdentifier: false, value: 'value'),
+          ],
         );
 
         expect(
@@ -152,6 +155,55 @@
         );
       });
 
+      test('observeValue returns object in an `InstanceManager`', () async {
+        final Completer<List<Object?>> argsCompleter =
+            Completer<List<Object?>>();
+
+        FoundationFlutterApis.instance = FoundationFlutterApis(
+          instanceManager: instanceManager,
+        );
+
+        object = NSObject.detached(
+          instanceManager: instanceManager,
+          observeValue: (
+            String keyPath,
+            NSObject object,
+            Map<NSKeyValueChangeKey, Object?> change,
+          ) {
+            argsCompleter.complete(<Object?>[keyPath, object, change]);
+          },
+        );
+        instanceManager.addHostCreatedInstance(object, 1);
+
+        final NSObject returnedObject = NSObject.detached(
+          instanceManager: instanceManager,
+        );
+        instanceManager.addHostCreatedInstance(returnedObject, 2);
+
+        FoundationFlutterApis.instance.object.observeValue(
+          1,
+          'keyPath',
+          1,
+          <NSKeyValueChangeKeyEnumData>[
+            NSKeyValueChangeKeyEnumData(value: NSKeyValueChangeKeyEnum.oldValue)
+          ],
+          <ObjectOrIdentifier?>[
+            ObjectOrIdentifier(isIdentifier: true, value: 2),
+          ],
+        );
+
+        expect(
+          argsCompleter.future,
+          completion(<Object?>[
+            'keyPath',
+            object,
+            <NSKeyValueChangeKey, Object?>{
+              NSKeyValueChangeKey.oldValue: returnedObject,
+            },
+          ]),
+        );
+      });
+
       test('NSObjectFlutterApi.dispose', () {
         FoundationFlutterApis.instance = FoundationFlutterApis(
           instanceManager: instanceManager,
@@ -166,5 +218,32 @@
         expect(instanceManager.containsIdentifier(1), isFalse);
       });
     });
+
+    group('NSUrl', () {
+      // Ensure the test host api is removed after each test run.
+      tearDown(() => TestNSUrlHostApi.setup(null));
+
+      test('getAbsoluteString', () async {
+        final MockTestNSUrlHostApi mockApi = MockTestNSUrlHostApi();
+        TestNSUrlHostApi.setup(mockApi);
+
+        final NSUrl url = NSUrl.detached(instanceManager: instanceManager);
+        instanceManager.addHostCreatedInstance(url, 0);
+
+        when(mockApi.getAbsoluteString(0)).thenReturn('myString');
+
+        expect(await url.getAbsoluteString(), 'myString');
+      });
+
+      test('Flutter API create', () {
+        final NSUrlFlutterApi flutterApi = NSUrlFlutterApiImpl(
+          instanceManager: instanceManager,
+        );
+
+        flutterApi.create(0);
+
+        expect(instanceManager.getInstanceWithWeakReference(0), isA<NSUrl>());
+      });
+    });
   });
 }
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/test/src/foundation/foundation_test.mocks.dart b/packages/webview_flutter/webview_flutter_wkwebview/test/src/foundation/foundation_test.mocks.dart
index 81c919e..a648fc6 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/test/src/foundation/foundation_test.mocks.dart
+++ b/packages/webview_flutter/webview_flutter_wkwebview/test/src/foundation/foundation_test.mocks.dart
@@ -73,3 +73,19 @@
         returnValueForMissingStub: null,
       );
 }
+
+/// A class which mocks [TestNSUrlHostApi].
+///
+/// See the documentation for Mockito's code generation for more information.
+class MockTestNSUrlHostApi extends _i1.Mock implements _i2.TestNSUrlHostApi {
+  MockTestNSUrlHostApi() {
+    _i1.throwOnMissingStub(this);
+  }
+
+  @override
+  String? getAbsoluteString(int? identifier) =>
+      (super.noSuchMethod(Invocation.method(
+        #getAbsoluteString,
+        [identifier],
+      )) as String?);
+}
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 abf3f79..dc7085b 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
@@ -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 'dart:async';
 import 'dart:math';
 // TODO(a14n): remove this import once Flutter 3.1 or later reaches stable (including flutter/flutter#104231)
 // ignore: unnecessary_import
@@ -23,6 +24,7 @@
 import 'webkit_webview_controller_test.mocks.dart';
 
 @GenerateMocks(<Type>[
+  NSUrl,
   UIScrollView,
   WKPreferences,
   WKUserContentController,
@@ -929,6 +931,70 @@
       expect(callbackProgress, 0);
     });
 
+    test('setPlatformNavigationDelegate onUrlChange', () async {
+      final MockWKWebView mockWebView = MockWKWebView();
+
+      late final void Function(
+        String keyPath,
+        NSObject object,
+        Map<NSKeyValueChangeKey, Object?> change,
+      ) webViewObserveValue;
+
+      final WebKitWebViewController controller = createControllerWithMocks(
+        createMockWebView: (
+          _, {
+          void Function(
+            String keyPath,
+            NSObject object,
+            Map<NSKeyValueChangeKey, Object?> change,
+          )? observeValue,
+        }) {
+          webViewObserveValue = observeValue!;
+          return mockWebView;
+        },
+      );
+
+      verify(
+        mockWebView.addObserver(
+          mockWebView,
+          keyPath: 'URL',
+          options: <NSKeyValueObservingOptions>{
+            NSKeyValueObservingOptions.newValue,
+          },
+        ),
+      );
+
+      final WebKitNavigationDelegate navigationDelegate =
+          WebKitNavigationDelegate(
+        const WebKitNavigationDelegateCreationParams(
+          webKitProxy: WebKitProxy(
+            createNavigationDelegate: CapturingNavigationDelegate.new,
+            createUIDelegate: WKUIDelegate.detached,
+          ),
+        ),
+      );
+
+      final Completer<UrlChange> urlChangeCompleter = Completer<UrlChange>();
+      navigationDelegate.setOnUrlChange(
+        (UrlChange change) => urlChangeCompleter.complete(change),
+      );
+
+      await controller.setPlatformNavigationDelegate(navigationDelegate);
+
+      final MockNSUrl mockNSUrl = MockNSUrl();
+      when(mockNSUrl.getAbsoluteString()).thenAnswer((_) {
+        return Future<String>.value('https://www.google.com');
+      });
+      webViewObserveValue(
+        'URL',
+        mockWebView,
+        <NSKeyValueChangeKey, Object?>{NSKeyValueChangeKey.newValue: mockNSUrl},
+      );
+
+      final UrlChange urlChange = await urlChangeCompleter.future;
+      expect(urlChange.url, 'https://www.google.com');
+    });
+
     test('webViewIdentifier', () {
       final InstanceManager instanceManager = InstanceManager(
         onWeakReferenceRemoved: (_) {},
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/test/webkit_webview_controller_test.mocks.dart b/packages/webview_flutter/webview_flutter_wkwebview/test/webkit_webview_controller_test.mocks.dart
index 184d0a6..9eb0397 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/test/webkit_webview_controller_test.mocks.dart
+++ b/packages/webview_flutter/webview_flutter_wkwebview/test/webkit_webview_controller_test.mocks.dart
@@ -3,15 +3,15 @@
 // Do not manually edit this file.
 
 // ignore_for_file: no_leading_underscores_for_library_prefixes
-import 'dart:async' as _i5;
-import 'dart:math' as _i2;
-import 'dart:ui' as _i6;
+import 'dart:async' as _i6;
+import 'dart:math' as _i3;
+import 'dart:ui' as _i7;
 
 import 'package:mockito/mockito.dart' as _i1;
 import 'package:webview_flutter_wkwebview/src/foundation/foundation.dart'
-    as _i7;
-import 'package:webview_flutter_wkwebview/src/ui_kit/ui_kit.dart' as _i3;
-import 'package:webview_flutter_wkwebview/src/web_kit/web_kit.dart' as _i4;
+    as _i2;
+import 'package:webview_flutter_wkwebview/src/ui_kit/ui_kit.dart' as _i4;
+import 'package:webview_flutter_wkwebview/src/web_kit/web_kit.dart' as _i5;
 
 // ignore_for_file: type=lint
 // ignore_for_file: avoid_redundant_argument_values
@@ -24,9 +24,8 @@
 // ignore_for_file: camel_case_types
 // ignore_for_file: subtype_of_sealed_class
 
-class _FakePoint_0<T extends num> extends _i1.SmartFake
-    implements _i2.Point<T> {
-  _FakePoint_0(
+class _FakeNSObject_0 extends _i1.SmartFake implements _i2.NSObject {
+  _FakeNSObject_0(
     Object parent,
     Invocation parentInvocation,
   ) : super(
@@ -35,8 +34,9 @@
         );
 }
 
-class _FakeUIScrollView_1 extends _i1.SmartFake implements _i3.UIScrollView {
-  _FakeUIScrollView_1(
+class _FakePoint_1<T extends num> extends _i1.SmartFake
+    implements _i3.Point<T> {
+  _FakePoint_1(
     Object parent,
     Invocation parentInvocation,
   ) : super(
@@ -45,8 +45,8 @@
         );
 }
 
-class _FakeWKPreferences_2 extends _i1.SmartFake implements _i4.WKPreferences {
-  _FakeWKPreferences_2(
+class _FakeUIScrollView_2 extends _i1.SmartFake implements _i4.UIScrollView {
+  _FakeUIScrollView_2(
     Object parent,
     Invocation parentInvocation,
   ) : super(
@@ -55,9 +55,8 @@
         );
 }
 
-class _FakeWKUserContentController_3 extends _i1.SmartFake
-    implements _i4.WKUserContentController {
-  _FakeWKUserContentController_3(
+class _FakeWKPreferences_3 extends _i1.SmartFake implements _i5.WKPreferences {
+  _FakeWKPreferences_3(
     Object parent,
     Invocation parentInvocation,
   ) : super(
@@ -66,9 +65,9 @@
         );
 }
 
-class _FakeWKHttpCookieStore_4 extends _i1.SmartFake
-    implements _i4.WKHttpCookieStore {
-  _FakeWKHttpCookieStore_4(
+class _FakeWKUserContentController_4 extends _i1.SmartFake
+    implements _i5.WKUserContentController {
+  _FakeWKUserContentController_4(
     Object parent,
     Invocation parentInvocation,
   ) : super(
@@ -77,9 +76,9 @@
         );
 }
 
-class _FakeWKWebsiteDataStore_5 extends _i1.SmartFake
-    implements _i4.WKWebsiteDataStore {
-  _FakeWKWebsiteDataStore_5(
+class _FakeWKHttpCookieStore_5 extends _i1.SmartFake
+    implements _i5.WKHttpCookieStore {
+  _FakeWKHttpCookieStore_5(
     Object parent,
     Invocation parentInvocation,
   ) : super(
@@ -88,9 +87,9 @@
         );
 }
 
-class _FakeWKWebViewConfiguration_6 extends _i1.SmartFake
-    implements _i4.WKWebViewConfiguration {
-  _FakeWKWebViewConfiguration_6(
+class _FakeWKWebsiteDataStore_6 extends _i1.SmartFake
+    implements _i5.WKWebsiteDataStore {
+  _FakeWKWebsiteDataStore_6(
     Object parent,
     Invocation parentInvocation,
   ) : super(
@@ -99,8 +98,9 @@
         );
 }
 
-class _FakeWKWebView_7 extends _i1.SmartFake implements _i4.WKWebView {
-  _FakeWKWebView_7(
+class _FakeWKWebViewConfiguration_7 extends _i1.SmartFake
+    implements _i5.WKWebViewConfiguration {
+  _FakeWKWebViewConfiguration_7(
     Object parent,
     Invocation parentInvocation,
   ) : super(
@@ -109,85 +109,159 @@
         );
 }
 
+class _FakeWKWebView_8 extends _i1.SmartFake implements _i5.WKWebView {
+  _FakeWKWebView_8(
+    Object parent,
+    Invocation parentInvocation,
+  ) : super(
+          parent,
+          parentInvocation,
+        );
+}
+
+/// A class which mocks [NSUrl].
+///
+/// See the documentation for Mockito's code generation for more information.
+class MockNSUrl extends _i1.Mock implements _i2.NSUrl {
+  MockNSUrl() {
+    _i1.throwOnMissingStub(this);
+  }
+
+  @override
+  _i6.Future<String?> getAbsoluteString() => (super.noSuchMethod(
+        Invocation.method(
+          #getAbsoluteString,
+          [],
+        ),
+        returnValue: _i6.Future<String?>.value(),
+      ) as _i6.Future<String?>);
+  @override
+  _i2.NSObject copy() => (super.noSuchMethod(
+        Invocation.method(
+          #copy,
+          [],
+        ),
+        returnValue: _FakeNSObject_0(
+          this,
+          Invocation.method(
+            #copy,
+            [],
+          ),
+        ),
+      ) as _i2.NSObject);
+  @override
+  _i6.Future<void> addObserver(
+    _i2.NSObject? observer, {
+    required String? keyPath,
+    required Set<_i2.NSKeyValueObservingOptions>? options,
+  }) =>
+      (super.noSuchMethod(
+        Invocation.method(
+          #addObserver,
+          [observer],
+          {
+            #keyPath: keyPath,
+            #options: options,
+          },
+        ),
+        returnValue: _i6.Future<void>.value(),
+        returnValueForMissingStub: _i6.Future<void>.value(),
+      ) as _i6.Future<void>);
+  @override
+  _i6.Future<void> removeObserver(
+    _i2.NSObject? observer, {
+    required String? keyPath,
+  }) =>
+      (super.noSuchMethod(
+        Invocation.method(
+          #removeObserver,
+          [observer],
+          {#keyPath: keyPath},
+        ),
+        returnValue: _i6.Future<void>.value(),
+        returnValueForMissingStub: _i6.Future<void>.value(),
+      ) as _i6.Future<void>);
+}
+
 /// A class which mocks [UIScrollView].
 ///
 /// See the documentation for Mockito's code generation for more information.
 // ignore: must_be_immutable
-class MockUIScrollView extends _i1.Mock implements _i3.UIScrollView {
+class MockUIScrollView extends _i1.Mock implements _i4.UIScrollView {
   MockUIScrollView() {
     _i1.throwOnMissingStub(this);
   }
 
   @override
-  _i5.Future<_i2.Point<double>> getContentOffset() => (super.noSuchMethod(
+  _i6.Future<_i3.Point<double>> getContentOffset() => (super.noSuchMethod(
         Invocation.method(
           #getContentOffset,
           [],
         ),
-        returnValue: _i5.Future<_i2.Point<double>>.value(_FakePoint_0<double>(
+        returnValue: _i6.Future<_i3.Point<double>>.value(_FakePoint_1<double>(
           this,
           Invocation.method(
             #getContentOffset,
             [],
           ),
         )),
-      ) as _i5.Future<_i2.Point<double>>);
+      ) as _i6.Future<_i3.Point<double>>);
   @override
-  _i5.Future<void> scrollBy(_i2.Point<double>? offset) => (super.noSuchMethod(
+  _i6.Future<void> scrollBy(_i3.Point<double>? offset) => (super.noSuchMethod(
         Invocation.method(
           #scrollBy,
           [offset],
         ),
-        returnValue: _i5.Future<void>.value(),
-        returnValueForMissingStub: _i5.Future<void>.value(),
-      ) as _i5.Future<void>);
+        returnValue: _i6.Future<void>.value(),
+        returnValueForMissingStub: _i6.Future<void>.value(),
+      ) as _i6.Future<void>);
   @override
-  _i5.Future<void> setContentOffset(_i2.Point<double>? offset) =>
+  _i6.Future<void> setContentOffset(_i3.Point<double>? offset) =>
       (super.noSuchMethod(
         Invocation.method(
           #setContentOffset,
           [offset],
         ),
-        returnValue: _i5.Future<void>.value(),
-        returnValueForMissingStub: _i5.Future<void>.value(),
-      ) as _i5.Future<void>);
+        returnValue: _i6.Future<void>.value(),
+        returnValueForMissingStub: _i6.Future<void>.value(),
+      ) as _i6.Future<void>);
   @override
-  _i3.UIScrollView copy() => (super.noSuchMethod(
+  _i4.UIScrollView copy() => (super.noSuchMethod(
         Invocation.method(
           #copy,
           [],
         ),
-        returnValue: _FakeUIScrollView_1(
+        returnValue: _FakeUIScrollView_2(
           this,
           Invocation.method(
             #copy,
             [],
           ),
         ),
-      ) as _i3.UIScrollView);
+      ) as _i4.UIScrollView);
   @override
-  _i5.Future<void> setBackgroundColor(_i6.Color? color) => (super.noSuchMethod(
+  _i6.Future<void> setBackgroundColor(_i7.Color? color) => (super.noSuchMethod(
         Invocation.method(
           #setBackgroundColor,
           [color],
         ),
-        returnValue: _i5.Future<void>.value(),
-        returnValueForMissingStub: _i5.Future<void>.value(),
-      ) as _i5.Future<void>);
+        returnValue: _i6.Future<void>.value(),
+        returnValueForMissingStub: _i6.Future<void>.value(),
+      ) as _i6.Future<void>);
   @override
-  _i5.Future<void> setOpaque(bool? opaque) => (super.noSuchMethod(
+  _i6.Future<void> setOpaque(bool? opaque) => (super.noSuchMethod(
         Invocation.method(
           #setOpaque,
           [opaque],
         ),
-        returnValue: _i5.Future<void>.value(),
-        returnValueForMissingStub: _i5.Future<void>.value(),
-      ) as _i5.Future<void>);
+        returnValue: _i6.Future<void>.value(),
+        returnValueForMissingStub: _i6.Future<void>.value(),
+      ) as _i6.Future<void>);
   @override
-  _i5.Future<void> addObserver(
-    _i7.NSObject? observer, {
+  _i6.Future<void> addObserver(
+    _i2.NSObject? observer, {
     required String? keyPath,
-    required Set<_i7.NSKeyValueObservingOptions>? options,
+    required Set<_i2.NSKeyValueObservingOptions>? options,
   }) =>
       (super.noSuchMethod(
         Invocation.method(
@@ -198,12 +272,12 @@
             #options: options,
           },
         ),
-        returnValue: _i5.Future<void>.value(),
-        returnValueForMissingStub: _i5.Future<void>.value(),
-      ) as _i5.Future<void>);
+        returnValue: _i6.Future<void>.value(),
+        returnValueForMissingStub: _i6.Future<void>.value(),
+      ) as _i6.Future<void>);
   @override
-  _i5.Future<void> removeObserver(
-    _i7.NSObject? observer, {
+  _i6.Future<void> removeObserver(
+    _i2.NSObject? observer, {
     required String? keyPath,
   }) =>
       (super.noSuchMethod(
@@ -212,48 +286,48 @@
           [observer],
           {#keyPath: keyPath},
         ),
-        returnValue: _i5.Future<void>.value(),
-        returnValueForMissingStub: _i5.Future<void>.value(),
-      ) as _i5.Future<void>);
+        returnValue: _i6.Future<void>.value(),
+        returnValueForMissingStub: _i6.Future<void>.value(),
+      ) as _i6.Future<void>);
 }
 
 /// A class which mocks [WKPreferences].
 ///
 /// See the documentation for Mockito's code generation for more information.
 // ignore: must_be_immutable
-class MockWKPreferences extends _i1.Mock implements _i4.WKPreferences {
+class MockWKPreferences extends _i1.Mock implements _i5.WKPreferences {
   MockWKPreferences() {
     _i1.throwOnMissingStub(this);
   }
 
   @override
-  _i5.Future<void> setJavaScriptEnabled(bool? enabled) => (super.noSuchMethod(
+  _i6.Future<void> setJavaScriptEnabled(bool? enabled) => (super.noSuchMethod(
         Invocation.method(
           #setJavaScriptEnabled,
           [enabled],
         ),
-        returnValue: _i5.Future<void>.value(),
-        returnValueForMissingStub: _i5.Future<void>.value(),
-      ) as _i5.Future<void>);
+        returnValue: _i6.Future<void>.value(),
+        returnValueForMissingStub: _i6.Future<void>.value(),
+      ) as _i6.Future<void>);
   @override
-  _i4.WKPreferences copy() => (super.noSuchMethod(
+  _i5.WKPreferences copy() => (super.noSuchMethod(
         Invocation.method(
           #copy,
           [],
         ),
-        returnValue: _FakeWKPreferences_2(
+        returnValue: _FakeWKPreferences_3(
           this,
           Invocation.method(
             #copy,
             [],
           ),
         ),
-      ) as _i4.WKPreferences);
+      ) as _i5.WKPreferences);
   @override
-  _i5.Future<void> addObserver(
-    _i7.NSObject? observer, {
+  _i6.Future<void> addObserver(
+    _i2.NSObject? observer, {
     required String? keyPath,
-    required Set<_i7.NSKeyValueObservingOptions>? options,
+    required Set<_i2.NSKeyValueObservingOptions>? options,
   }) =>
       (super.noSuchMethod(
         Invocation.method(
@@ -264,12 +338,12 @@
             #options: options,
           },
         ),
-        returnValue: _i5.Future<void>.value(),
-        returnValueForMissingStub: _i5.Future<void>.value(),
-      ) as _i5.Future<void>);
+        returnValue: _i6.Future<void>.value(),
+        returnValueForMissingStub: _i6.Future<void>.value(),
+      ) as _i6.Future<void>);
   @override
-  _i5.Future<void> removeObserver(
-    _i7.NSObject? observer, {
+  _i6.Future<void> removeObserver(
+    _i2.NSObject? observer, {
     required String? keyPath,
   }) =>
       (super.noSuchMethod(
@@ -278,9 +352,9 @@
           [observer],
           {#keyPath: keyPath},
         ),
-        returnValue: _i5.Future<void>.value(),
-        returnValueForMissingStub: _i5.Future<void>.value(),
-      ) as _i5.Future<void>);
+        returnValue: _i6.Future<void>.value(),
+        returnValueForMissingStub: _i6.Future<void>.value(),
+      ) as _i6.Future<void>);
 }
 
 /// A class which mocks [WKUserContentController].
@@ -288,14 +362,14 @@
 /// See the documentation for Mockito's code generation for more information.
 // ignore: must_be_immutable
 class MockWKUserContentController extends _i1.Mock
-    implements _i4.WKUserContentController {
+    implements _i5.WKUserContentController {
   MockWKUserContentController() {
     _i1.throwOnMissingStub(this);
   }
 
   @override
-  _i5.Future<void> addScriptMessageHandler(
-    _i4.WKScriptMessageHandler? handler,
+  _i6.Future<void> addScriptMessageHandler(
+    _i5.WKScriptMessageHandler? handler,
     String? name,
   ) =>
       (super.noSuchMethod(
@@ -306,66 +380,66 @@
             name,
           ],
         ),
-        returnValue: _i5.Future<void>.value(),
-        returnValueForMissingStub: _i5.Future<void>.value(),
-      ) as _i5.Future<void>);
+        returnValue: _i6.Future<void>.value(),
+        returnValueForMissingStub: _i6.Future<void>.value(),
+      ) as _i6.Future<void>);
   @override
-  _i5.Future<void> removeScriptMessageHandler(String? name) =>
+  _i6.Future<void> removeScriptMessageHandler(String? name) =>
       (super.noSuchMethod(
         Invocation.method(
           #removeScriptMessageHandler,
           [name],
         ),
-        returnValue: _i5.Future<void>.value(),
-        returnValueForMissingStub: _i5.Future<void>.value(),
-      ) as _i5.Future<void>);
+        returnValue: _i6.Future<void>.value(),
+        returnValueForMissingStub: _i6.Future<void>.value(),
+      ) as _i6.Future<void>);
   @override
-  _i5.Future<void> removeAllScriptMessageHandlers() => (super.noSuchMethod(
+  _i6.Future<void> removeAllScriptMessageHandlers() => (super.noSuchMethod(
         Invocation.method(
           #removeAllScriptMessageHandlers,
           [],
         ),
-        returnValue: _i5.Future<void>.value(),
-        returnValueForMissingStub: _i5.Future<void>.value(),
-      ) as _i5.Future<void>);
+        returnValue: _i6.Future<void>.value(),
+        returnValueForMissingStub: _i6.Future<void>.value(),
+      ) as _i6.Future<void>);
   @override
-  _i5.Future<void> addUserScript(_i4.WKUserScript? userScript) =>
+  _i6.Future<void> addUserScript(_i5.WKUserScript? userScript) =>
       (super.noSuchMethod(
         Invocation.method(
           #addUserScript,
           [userScript],
         ),
-        returnValue: _i5.Future<void>.value(),
-        returnValueForMissingStub: _i5.Future<void>.value(),
-      ) as _i5.Future<void>);
+        returnValue: _i6.Future<void>.value(),
+        returnValueForMissingStub: _i6.Future<void>.value(),
+      ) as _i6.Future<void>);
   @override
-  _i5.Future<void> removeAllUserScripts() => (super.noSuchMethod(
+  _i6.Future<void> removeAllUserScripts() => (super.noSuchMethod(
         Invocation.method(
           #removeAllUserScripts,
           [],
         ),
-        returnValue: _i5.Future<void>.value(),
-        returnValueForMissingStub: _i5.Future<void>.value(),
-      ) as _i5.Future<void>);
+        returnValue: _i6.Future<void>.value(),
+        returnValueForMissingStub: _i6.Future<void>.value(),
+      ) as _i6.Future<void>);
   @override
-  _i4.WKUserContentController copy() => (super.noSuchMethod(
+  _i5.WKUserContentController copy() => (super.noSuchMethod(
         Invocation.method(
           #copy,
           [],
         ),
-        returnValue: _FakeWKUserContentController_3(
+        returnValue: _FakeWKUserContentController_4(
           this,
           Invocation.method(
             #copy,
             [],
           ),
         ),
-      ) as _i4.WKUserContentController);
+      ) as _i5.WKUserContentController);
   @override
-  _i5.Future<void> addObserver(
-    _i7.NSObject? observer, {
+  _i6.Future<void> addObserver(
+    _i2.NSObject? observer, {
     required String? keyPath,
-    required Set<_i7.NSKeyValueObservingOptions>? options,
+    required Set<_i2.NSKeyValueObservingOptions>? options,
   }) =>
       (super.noSuchMethod(
         Invocation.method(
@@ -376,12 +450,12 @@
             #options: options,
           },
         ),
-        returnValue: _i5.Future<void>.value(),
-        returnValueForMissingStub: _i5.Future<void>.value(),
-      ) as _i5.Future<void>);
+        returnValue: _i6.Future<void>.value(),
+        returnValueForMissingStub: _i6.Future<void>.value(),
+      ) as _i6.Future<void>);
   @override
-  _i5.Future<void> removeObserver(
-    _i7.NSObject? observer, {
+  _i6.Future<void> removeObserver(
+    _i2.NSObject? observer, {
     required String? keyPath,
   }) =>
       (super.noSuchMethod(
@@ -390,9 +464,9 @@
           [observer],
           {#keyPath: keyPath},
         ),
-        returnValue: _i5.Future<void>.value(),
-        returnValueForMissingStub: _i5.Future<void>.value(),
-      ) as _i5.Future<void>);
+        returnValue: _i6.Future<void>.value(),
+        returnValueForMissingStub: _i6.Future<void>.value(),
+      ) as _i6.Future<void>);
 }
 
 /// A class which mocks [WKWebsiteDataStore].
@@ -400,22 +474,22 @@
 /// See the documentation for Mockito's code generation for more information.
 // ignore: must_be_immutable
 class MockWKWebsiteDataStore extends _i1.Mock
-    implements _i4.WKWebsiteDataStore {
+    implements _i5.WKWebsiteDataStore {
   MockWKWebsiteDataStore() {
     _i1.throwOnMissingStub(this);
   }
 
   @override
-  _i4.WKHttpCookieStore get httpCookieStore => (super.noSuchMethod(
+  _i5.WKHttpCookieStore get httpCookieStore => (super.noSuchMethod(
         Invocation.getter(#httpCookieStore),
-        returnValue: _FakeWKHttpCookieStore_4(
+        returnValue: _FakeWKHttpCookieStore_5(
           this,
           Invocation.getter(#httpCookieStore),
         ),
-      ) as _i4.WKHttpCookieStore);
+      ) as _i5.WKHttpCookieStore);
   @override
-  _i5.Future<bool> removeDataOfTypes(
-    Set<_i4.WKWebsiteDataType>? dataTypes,
+  _i6.Future<bool> removeDataOfTypes(
+    Set<_i5.WKWebsiteDataType>? dataTypes,
     DateTime? since,
   ) =>
       (super.noSuchMethod(
@@ -426,27 +500,27 @@
             since,
           ],
         ),
-        returnValue: _i5.Future<bool>.value(false),
-      ) as _i5.Future<bool>);
+        returnValue: _i6.Future<bool>.value(false),
+      ) as _i6.Future<bool>);
   @override
-  _i4.WKWebsiteDataStore copy() => (super.noSuchMethod(
+  _i5.WKWebsiteDataStore copy() => (super.noSuchMethod(
         Invocation.method(
           #copy,
           [],
         ),
-        returnValue: _FakeWKWebsiteDataStore_5(
+        returnValue: _FakeWKWebsiteDataStore_6(
           this,
           Invocation.method(
             #copy,
             [],
           ),
         ),
-      ) as _i4.WKWebsiteDataStore);
+      ) as _i5.WKWebsiteDataStore);
   @override
-  _i5.Future<void> addObserver(
-    _i7.NSObject? observer, {
+  _i6.Future<void> addObserver(
+    _i2.NSObject? observer, {
     required String? keyPath,
-    required Set<_i7.NSKeyValueObservingOptions>? options,
+    required Set<_i2.NSKeyValueObservingOptions>? options,
   }) =>
       (super.noSuchMethod(
         Invocation.method(
@@ -457,12 +531,12 @@
             #options: options,
           },
         ),
-        returnValue: _i5.Future<void>.value(),
-        returnValueForMissingStub: _i5.Future<void>.value(),
-      ) as _i5.Future<void>);
+        returnValue: _i6.Future<void>.value(),
+        returnValueForMissingStub: _i6.Future<void>.value(),
+      ) as _i6.Future<void>);
   @override
-  _i5.Future<void> removeObserver(
-    _i7.NSObject? observer, {
+  _i6.Future<void> removeObserver(
+    _i2.NSObject? observer, {
     required String? keyPath,
   }) =>
       (super.noSuchMethod(
@@ -471,84 +545,84 @@
           [observer],
           {#keyPath: keyPath},
         ),
-        returnValue: _i5.Future<void>.value(),
-        returnValueForMissingStub: _i5.Future<void>.value(),
-      ) as _i5.Future<void>);
+        returnValue: _i6.Future<void>.value(),
+        returnValueForMissingStub: _i6.Future<void>.value(),
+      ) as _i6.Future<void>);
 }
 
 /// A class which mocks [WKWebView].
 ///
 /// See the documentation for Mockito's code generation for more information.
 // ignore: must_be_immutable
-class MockWKWebView extends _i1.Mock implements _i4.WKWebView {
+class MockWKWebView extends _i1.Mock implements _i5.WKWebView {
   MockWKWebView() {
     _i1.throwOnMissingStub(this);
   }
 
   @override
-  _i4.WKWebViewConfiguration get configuration => (super.noSuchMethod(
+  _i5.WKWebViewConfiguration get configuration => (super.noSuchMethod(
         Invocation.getter(#configuration),
-        returnValue: _FakeWKWebViewConfiguration_6(
+        returnValue: _FakeWKWebViewConfiguration_7(
           this,
           Invocation.getter(#configuration),
         ),
-      ) as _i4.WKWebViewConfiguration);
+      ) as _i5.WKWebViewConfiguration);
   @override
-  _i3.UIScrollView get scrollView => (super.noSuchMethod(
+  _i4.UIScrollView get scrollView => (super.noSuchMethod(
         Invocation.getter(#scrollView),
-        returnValue: _FakeUIScrollView_1(
+        returnValue: _FakeUIScrollView_2(
           this,
           Invocation.getter(#scrollView),
         ),
-      ) as _i3.UIScrollView);
+      ) as _i4.UIScrollView);
   @override
-  _i5.Future<void> setUIDelegate(_i4.WKUIDelegate? delegate) =>
+  _i6.Future<void> setUIDelegate(_i5.WKUIDelegate? delegate) =>
       (super.noSuchMethod(
         Invocation.method(
           #setUIDelegate,
           [delegate],
         ),
-        returnValue: _i5.Future<void>.value(),
-        returnValueForMissingStub: _i5.Future<void>.value(),
-      ) as _i5.Future<void>);
+        returnValue: _i6.Future<void>.value(),
+        returnValueForMissingStub: _i6.Future<void>.value(),
+      ) as _i6.Future<void>);
   @override
-  _i5.Future<void> setNavigationDelegate(_i4.WKNavigationDelegate? delegate) =>
+  _i6.Future<void> setNavigationDelegate(_i5.WKNavigationDelegate? delegate) =>
       (super.noSuchMethod(
         Invocation.method(
           #setNavigationDelegate,
           [delegate],
         ),
-        returnValue: _i5.Future<void>.value(),
-        returnValueForMissingStub: _i5.Future<void>.value(),
-      ) as _i5.Future<void>);
+        returnValue: _i6.Future<void>.value(),
+        returnValueForMissingStub: _i6.Future<void>.value(),
+      ) as _i6.Future<void>);
   @override
-  _i5.Future<String?> getUrl() => (super.noSuchMethod(
+  _i6.Future<String?> getUrl() => (super.noSuchMethod(
         Invocation.method(
           #getUrl,
           [],
         ),
-        returnValue: _i5.Future<String?>.value(),
-      ) as _i5.Future<String?>);
+        returnValue: _i6.Future<String?>.value(),
+      ) as _i6.Future<String?>);
   @override
-  _i5.Future<double> getEstimatedProgress() => (super.noSuchMethod(
+  _i6.Future<double> getEstimatedProgress() => (super.noSuchMethod(
         Invocation.method(
           #getEstimatedProgress,
           [],
         ),
-        returnValue: _i5.Future<double>.value(0.0),
-      ) as _i5.Future<double>);
+        returnValue: _i6.Future<double>.value(0.0),
+      ) as _i6.Future<double>);
   @override
-  _i5.Future<void> loadRequest(_i7.NSUrlRequest? request) =>
+  _i6.Future<void> loadRequest(_i2.NSUrlRequest? request) =>
       (super.noSuchMethod(
         Invocation.method(
           #loadRequest,
           [request],
         ),
-        returnValue: _i5.Future<void>.value(),
-        returnValueForMissingStub: _i5.Future<void>.value(),
-      ) as _i5.Future<void>);
+        returnValue: _i6.Future<void>.value(),
+        returnValueForMissingStub: _i6.Future<void>.value(),
+      ) as _i6.Future<void>);
   @override
-  _i5.Future<void> loadHtmlString(
+  _i6.Future<void> loadHtmlString(
     String? string, {
     String? baseUrl,
   }) =>
@@ -558,11 +632,11 @@
           [string],
           {#baseUrl: baseUrl},
         ),
-        returnValue: _i5.Future<void>.value(),
-        returnValueForMissingStub: _i5.Future<void>.value(),
-      ) as _i5.Future<void>);
+        returnValue: _i6.Future<void>.value(),
+        returnValueForMissingStub: _i6.Future<void>.value(),
+      ) as _i6.Future<void>);
   @override
-  _i5.Future<void> loadFileUrl(
+  _i6.Future<void> loadFileUrl(
     String? url, {
     required String? readAccessUrl,
   }) =>
@@ -572,134 +646,134 @@
           [url],
           {#readAccessUrl: readAccessUrl},
         ),
-        returnValue: _i5.Future<void>.value(),
-        returnValueForMissingStub: _i5.Future<void>.value(),
-      ) as _i5.Future<void>);
+        returnValue: _i6.Future<void>.value(),
+        returnValueForMissingStub: _i6.Future<void>.value(),
+      ) as _i6.Future<void>);
   @override
-  _i5.Future<void> loadFlutterAsset(String? key) => (super.noSuchMethod(
+  _i6.Future<void> loadFlutterAsset(String? key) => (super.noSuchMethod(
         Invocation.method(
           #loadFlutterAsset,
           [key],
         ),
-        returnValue: _i5.Future<void>.value(),
-        returnValueForMissingStub: _i5.Future<void>.value(),
-      ) as _i5.Future<void>);
+        returnValue: _i6.Future<void>.value(),
+        returnValueForMissingStub: _i6.Future<void>.value(),
+      ) as _i6.Future<void>);
   @override
-  _i5.Future<bool> canGoBack() => (super.noSuchMethod(
+  _i6.Future<bool> canGoBack() => (super.noSuchMethod(
         Invocation.method(
           #canGoBack,
           [],
         ),
-        returnValue: _i5.Future<bool>.value(false),
-      ) as _i5.Future<bool>);
+        returnValue: _i6.Future<bool>.value(false),
+      ) as _i6.Future<bool>);
   @override
-  _i5.Future<bool> canGoForward() => (super.noSuchMethod(
+  _i6.Future<bool> canGoForward() => (super.noSuchMethod(
         Invocation.method(
           #canGoForward,
           [],
         ),
-        returnValue: _i5.Future<bool>.value(false),
-      ) as _i5.Future<bool>);
+        returnValue: _i6.Future<bool>.value(false),
+      ) as _i6.Future<bool>);
   @override
-  _i5.Future<void> goBack() => (super.noSuchMethod(
+  _i6.Future<void> goBack() => (super.noSuchMethod(
         Invocation.method(
           #goBack,
           [],
         ),
-        returnValue: _i5.Future<void>.value(),
-        returnValueForMissingStub: _i5.Future<void>.value(),
-      ) as _i5.Future<void>);
+        returnValue: _i6.Future<void>.value(),
+        returnValueForMissingStub: _i6.Future<void>.value(),
+      ) as _i6.Future<void>);
   @override
-  _i5.Future<void> goForward() => (super.noSuchMethod(
+  _i6.Future<void> goForward() => (super.noSuchMethod(
         Invocation.method(
           #goForward,
           [],
         ),
-        returnValue: _i5.Future<void>.value(),
-        returnValueForMissingStub: _i5.Future<void>.value(),
-      ) as _i5.Future<void>);
+        returnValue: _i6.Future<void>.value(),
+        returnValueForMissingStub: _i6.Future<void>.value(),
+      ) as _i6.Future<void>);
   @override
-  _i5.Future<void> reload() => (super.noSuchMethod(
+  _i6.Future<void> reload() => (super.noSuchMethod(
         Invocation.method(
           #reload,
           [],
         ),
-        returnValue: _i5.Future<void>.value(),
-        returnValueForMissingStub: _i5.Future<void>.value(),
-      ) as _i5.Future<void>);
+        returnValue: _i6.Future<void>.value(),
+        returnValueForMissingStub: _i6.Future<void>.value(),
+      ) as _i6.Future<void>);
   @override
-  _i5.Future<String?> getTitle() => (super.noSuchMethod(
+  _i6.Future<String?> getTitle() => (super.noSuchMethod(
         Invocation.method(
           #getTitle,
           [],
         ),
-        returnValue: _i5.Future<String?>.value(),
-      ) as _i5.Future<String?>);
+        returnValue: _i6.Future<String?>.value(),
+      ) as _i6.Future<String?>);
   @override
-  _i5.Future<void> setAllowsBackForwardNavigationGestures(bool? allow) =>
+  _i6.Future<void> setAllowsBackForwardNavigationGestures(bool? allow) =>
       (super.noSuchMethod(
         Invocation.method(
           #setAllowsBackForwardNavigationGestures,
           [allow],
         ),
-        returnValue: _i5.Future<void>.value(),
-        returnValueForMissingStub: _i5.Future<void>.value(),
-      ) as _i5.Future<void>);
+        returnValue: _i6.Future<void>.value(),
+        returnValueForMissingStub: _i6.Future<void>.value(),
+      ) as _i6.Future<void>);
   @override
-  _i5.Future<void> setCustomUserAgent(String? userAgent) => (super.noSuchMethod(
+  _i6.Future<void> setCustomUserAgent(String? userAgent) => (super.noSuchMethod(
         Invocation.method(
           #setCustomUserAgent,
           [userAgent],
         ),
-        returnValue: _i5.Future<void>.value(),
-        returnValueForMissingStub: _i5.Future<void>.value(),
-      ) as _i5.Future<void>);
+        returnValue: _i6.Future<void>.value(),
+        returnValueForMissingStub: _i6.Future<void>.value(),
+      ) as _i6.Future<void>);
   @override
-  _i5.Future<Object?> evaluateJavaScript(String? javaScriptString) =>
+  _i6.Future<Object?> evaluateJavaScript(String? javaScriptString) =>
       (super.noSuchMethod(
         Invocation.method(
           #evaluateJavaScript,
           [javaScriptString],
         ),
-        returnValue: _i5.Future<Object?>.value(),
-      ) as _i5.Future<Object?>);
+        returnValue: _i6.Future<Object?>.value(),
+      ) as _i6.Future<Object?>);
   @override
-  _i4.WKWebView copy() => (super.noSuchMethod(
+  _i5.WKWebView copy() => (super.noSuchMethod(
         Invocation.method(
           #copy,
           [],
         ),
-        returnValue: _FakeWKWebView_7(
+        returnValue: _FakeWKWebView_8(
           this,
           Invocation.method(
             #copy,
             [],
           ),
         ),
-      ) as _i4.WKWebView);
+      ) as _i5.WKWebView);
   @override
-  _i5.Future<void> setBackgroundColor(_i6.Color? color) => (super.noSuchMethod(
+  _i6.Future<void> setBackgroundColor(_i7.Color? color) => (super.noSuchMethod(
         Invocation.method(
           #setBackgroundColor,
           [color],
         ),
-        returnValue: _i5.Future<void>.value(),
-        returnValueForMissingStub: _i5.Future<void>.value(),
-      ) as _i5.Future<void>);
+        returnValue: _i6.Future<void>.value(),
+        returnValueForMissingStub: _i6.Future<void>.value(),
+      ) as _i6.Future<void>);
   @override
-  _i5.Future<void> setOpaque(bool? opaque) => (super.noSuchMethod(
+  _i6.Future<void> setOpaque(bool? opaque) => (super.noSuchMethod(
         Invocation.method(
           #setOpaque,
           [opaque],
         ),
-        returnValue: _i5.Future<void>.value(),
-        returnValueForMissingStub: _i5.Future<void>.value(),
-      ) as _i5.Future<void>);
+        returnValue: _i6.Future<void>.value(),
+        returnValueForMissingStub: _i6.Future<void>.value(),
+      ) as _i6.Future<void>);
   @override
-  _i5.Future<void> addObserver(
-    _i7.NSObject? observer, {
+  _i6.Future<void> addObserver(
+    _i2.NSObject? observer, {
     required String? keyPath,
-    required Set<_i7.NSKeyValueObservingOptions>? options,
+    required Set<_i2.NSKeyValueObservingOptions>? options,
   }) =>
       (super.noSuchMethod(
         Invocation.method(
@@ -710,12 +784,12 @@
             #options: options,
           },
         ),
-        returnValue: _i5.Future<void>.value(),
-        returnValueForMissingStub: _i5.Future<void>.value(),
-      ) as _i5.Future<void>);
+        returnValue: _i6.Future<void>.value(),
+        returnValueForMissingStub: _i6.Future<void>.value(),
+      ) as _i6.Future<void>);
   @override
-  _i5.Future<void> removeObserver(
-    _i7.NSObject? observer, {
+  _i6.Future<void> removeObserver(
+    _i2.NSObject? observer, {
     required String? keyPath,
   }) =>
       (super.noSuchMethod(
@@ -724,9 +798,9 @@
           [observer],
           {#keyPath: keyPath},
         ),
-        returnValue: _i5.Future<void>.value(),
-        returnValueForMissingStub: _i5.Future<void>.value(),
-      ) as _i5.Future<void>);
+        returnValue: _i6.Future<void>.value(),
+        returnValueForMissingStub: _i6.Future<void>.value(),
+      ) as _i6.Future<void>);
 }
 
 /// A class which mocks [WKWebViewConfiguration].
@@ -734,75 +808,75 @@
 /// See the documentation for Mockito's code generation for more information.
 // ignore: must_be_immutable
 class MockWKWebViewConfiguration extends _i1.Mock
-    implements _i4.WKWebViewConfiguration {
+    implements _i5.WKWebViewConfiguration {
   MockWKWebViewConfiguration() {
     _i1.throwOnMissingStub(this);
   }
 
   @override
-  _i4.WKUserContentController get userContentController => (super.noSuchMethod(
+  _i5.WKUserContentController get userContentController => (super.noSuchMethod(
         Invocation.getter(#userContentController),
-        returnValue: _FakeWKUserContentController_3(
+        returnValue: _FakeWKUserContentController_4(
           this,
           Invocation.getter(#userContentController),
         ),
-      ) as _i4.WKUserContentController);
+      ) as _i5.WKUserContentController);
   @override
-  _i4.WKPreferences get preferences => (super.noSuchMethod(
+  _i5.WKPreferences get preferences => (super.noSuchMethod(
         Invocation.getter(#preferences),
-        returnValue: _FakeWKPreferences_2(
+        returnValue: _FakeWKPreferences_3(
           this,
           Invocation.getter(#preferences),
         ),
-      ) as _i4.WKPreferences);
+      ) as _i5.WKPreferences);
   @override
-  _i4.WKWebsiteDataStore get websiteDataStore => (super.noSuchMethod(
+  _i5.WKWebsiteDataStore get websiteDataStore => (super.noSuchMethod(
         Invocation.getter(#websiteDataStore),
-        returnValue: _FakeWKWebsiteDataStore_5(
+        returnValue: _FakeWKWebsiteDataStore_6(
           this,
           Invocation.getter(#websiteDataStore),
         ),
-      ) as _i4.WKWebsiteDataStore);
+      ) as _i5.WKWebsiteDataStore);
   @override
-  _i5.Future<void> setAllowsInlineMediaPlayback(bool? allow) =>
+  _i6.Future<void> setAllowsInlineMediaPlayback(bool? allow) =>
       (super.noSuchMethod(
         Invocation.method(
           #setAllowsInlineMediaPlayback,
           [allow],
         ),
-        returnValue: _i5.Future<void>.value(),
-        returnValueForMissingStub: _i5.Future<void>.value(),
-      ) as _i5.Future<void>);
+        returnValue: _i6.Future<void>.value(),
+        returnValueForMissingStub: _i6.Future<void>.value(),
+      ) as _i6.Future<void>);
   @override
-  _i5.Future<void> setMediaTypesRequiringUserActionForPlayback(
-          Set<_i4.WKAudiovisualMediaType>? types) =>
+  _i6.Future<void> setMediaTypesRequiringUserActionForPlayback(
+          Set<_i5.WKAudiovisualMediaType>? types) =>
       (super.noSuchMethod(
         Invocation.method(
           #setMediaTypesRequiringUserActionForPlayback,
           [types],
         ),
-        returnValue: _i5.Future<void>.value(),
-        returnValueForMissingStub: _i5.Future<void>.value(),
-      ) as _i5.Future<void>);
+        returnValue: _i6.Future<void>.value(),
+        returnValueForMissingStub: _i6.Future<void>.value(),
+      ) as _i6.Future<void>);
   @override
-  _i4.WKWebViewConfiguration copy() => (super.noSuchMethod(
+  _i5.WKWebViewConfiguration copy() => (super.noSuchMethod(
         Invocation.method(
           #copy,
           [],
         ),
-        returnValue: _FakeWKWebViewConfiguration_6(
+        returnValue: _FakeWKWebViewConfiguration_7(
           this,
           Invocation.method(
             #copy,
             [],
           ),
         ),
-      ) as _i4.WKWebViewConfiguration);
+      ) as _i5.WKWebViewConfiguration);
   @override
-  _i5.Future<void> addObserver(
-    _i7.NSObject? observer, {
+  _i6.Future<void> addObserver(
+    _i2.NSObject? observer, {
     required String? keyPath,
-    required Set<_i7.NSKeyValueObservingOptions>? options,
+    required Set<_i2.NSKeyValueObservingOptions>? options,
   }) =>
       (super.noSuchMethod(
         Invocation.method(
@@ -813,12 +887,12 @@
             #options: options,
           },
         ),
-        returnValue: _i5.Future<void>.value(),
-        returnValueForMissingStub: _i5.Future<void>.value(),
-      ) as _i5.Future<void>);
+        returnValue: _i6.Future<void>.value(),
+        returnValueForMissingStub: _i6.Future<void>.value(),
+      ) as _i6.Future<void>);
   @override
-  _i5.Future<void> removeObserver(
-    _i7.NSObject? observer, {
+  _i6.Future<void> removeObserver(
+    _i2.NSObject? observer, {
     required String? keyPath,
   }) =>
       (super.noSuchMethod(
@@ -827,7 +901,7 @@
           [observer],
           {#keyPath: keyPath},
         ),
-        returnValue: _i5.Future<void>.value(),
-        returnValueForMissingStub: _i5.Future<void>.value(),
-      ) as _i5.Future<void>);
+        returnValue: _i6.Future<void>.value(),
+        returnValueForMissingStub: _i6.Future<void>.value(),
+      ) as _i6.Future<void>);
 }