[webview_flutter][webview_flutter_android] Add android support for handling geolocation permissions (#3795)

This PR Add android support for handling geolocation permissions.
[(WebChromeClient.onGeolocationPermissionsShowPrompt)](https://developer.android.com/reference/android/webkit/WebChromeClient#onGeolocationPermissionsShowPrompt(java.lang.String,%20android.webkit.GeolocationPermissions.Callback)) api as a platform callback that notify the host application that web content from the specified origin is attempting to use the Geolocation API.

The host application should invoke the specified callback with the desired permission state. 

Fixes https://github.com/flutter/flutter/issues/27472
diff --git a/packages/webview_flutter/webview_flutter_android/AUTHORS b/packages/webview_flutter/webview_flutter_android/AUTHORS
index 22e2b0e..b664f36 100644
--- a/packages/webview_flutter/webview_flutter_android/AUTHORS
+++ b/packages/webview_flutter/webview_flutter_android/AUTHORS
@@ -66,4 +66,5 @@
 Rahul Raj <64.rahulraj@gmail.com>
 Maurits van Beusekom <maurits@baseflow.com>
 Nick Bradshaw <nickalasb@gmail.com>
+Kai Yu <yk3372@gmail.com>
 
diff --git a/packages/webview_flutter/webview_flutter_android/CHANGELOG.md b/packages/webview_flutter/webview_flutter_android/CHANGELOG.md
index 3160b85..adc5034 100644
--- a/packages/webview_flutter/webview_flutter_android/CHANGELOG.md
+++ b/packages/webview_flutter/webview_flutter_android/CHANGELOG.md
@@ -1,3 +1,8 @@
+## 3.8.0
+
+* Adds support for handling geolocation permissions. See
+  `AndroidWebViewController.setGeolocationPermissionsPromptCallbacks`.
+
 ## 3.7.1
 
 * Removes obsolete null checks on non-nullable values.
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 4dc43fa..cc52b0b 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
@@ -2589,6 +2589,33 @@
           new ArrayList<Object>(Arrays.asList(instanceIdArg, requestInstanceIdArg)),
           channelReply -> callback.reply(null));
     }
+    /** Callback to Dart function `WebChromeClient.onGeolocationPermissionsShowPrompt`. */
+    public void onGeolocationPermissionsShowPrompt(
+        @NonNull Long instanceIdArg,
+        @NonNull Long paramsInstanceIdArg,
+        @NonNull String originArg,
+        @NonNull Reply<Void> callback) {
+      BasicMessageChannel<Object> channel =
+          new BasicMessageChannel<>(
+              binaryMessenger,
+              "dev.flutter.pigeon.WebChromeClientFlutterApi.onGeolocationPermissionsShowPrompt",
+              getCodec());
+      channel.send(
+          new ArrayList<Object>(Arrays.asList(instanceIdArg, paramsInstanceIdArg, originArg)),
+          channelReply -> callback.reply(null));
+    }
+    /** Callback to Dart function `WebChromeClient.onGeolocationPermissionsHidePrompt`. */
+    public void onGeolocationPermissionsHidePrompt(
+        @NonNull Long identifierArg, @NonNull Reply<Void> callback) {
+      BasicMessageChannel<Object> channel =
+          new BasicMessageChannel<>(
+              binaryMessenger,
+              "dev.flutter.pigeon.WebChromeClientFlutterApi.onGeolocationPermissionsHidePrompt",
+              getCodec());
+      channel.send(
+          new ArrayList<Object>(Collections.singletonList(identifierArg)),
+          channelReply -> callback.reply(null));
+    }
   }
   /** Generated interface from Pigeon that represents a handler of messages from Flutter. */
   public interface WebStorageHostApi {
@@ -2839,4 +2866,106 @@
           channelReply -> callback.reply(null));
     }
   }
+  /**
+   * Host API for `GeolocationPermissionsCallback`.
+   *
+   * <p>This class may handle instantiating and adding native object instances that are attached to
+   * a Dart instance or handle method calls on the associated native class or an instance of the
+   * class.
+   *
+   * <p>See https://developer.android.com/reference/android/webkit/GeolocationPermissions.Callback.
+   *
+   * <p>Generated interface from Pigeon that represents a handler of messages from Flutter.
+   */
+  public interface GeolocationPermissionsCallbackHostApi {
+    /** Handles Dart method `GeolocationPermissionsCallback.invoke`. */
+    void invoke(
+        @NonNull Long instanceId,
+        @NonNull String origin,
+        @NonNull Boolean allow,
+        @NonNull Boolean retain);
+
+    /** The codec used by GeolocationPermissionsCallbackHostApi. */
+    static @NonNull MessageCodec<Object> getCodec() {
+      return new StandardMessageCodec();
+    }
+    /**
+     * Sets up an instance of `GeolocationPermissionsCallbackHostApi` to handle messages through the
+     * `binaryMessenger`.
+     */
+    static void setup(
+        @NonNull BinaryMessenger binaryMessenger,
+        @Nullable GeolocationPermissionsCallbackHostApi api) {
+      {
+        BasicMessageChannel<Object> channel =
+            new BasicMessageChannel<>(
+                binaryMessenger,
+                "dev.flutter.pigeon.GeolocationPermissionsCallbackHostApi.invoke",
+                getCodec());
+        if (api != null) {
+          channel.setMessageHandler(
+              (message, reply) -> {
+                ArrayList<Object> wrapped = new ArrayList<Object>();
+                ArrayList<Object> args = (ArrayList<Object>) message;
+                Number instanceIdArg = (Number) args.get(0);
+                String originArg = (String) args.get(1);
+                Boolean allowArg = (Boolean) args.get(2);
+                Boolean retainArg = (Boolean) args.get(3);
+                try {
+                  api.invoke(
+                      (instanceIdArg == null) ? null : instanceIdArg.longValue(),
+                      originArg,
+                      allowArg,
+                      retainArg);
+                  wrapped.add(0, null);
+                } catch (Throwable exception) {
+                  ArrayList<Object> wrappedError = wrapError(exception);
+                  wrapped = wrappedError;
+                }
+                reply.reply(wrapped);
+              });
+        } else {
+          channel.setMessageHandler(null);
+        }
+      }
+    }
+  }
+  /**
+   * Flutter API for `GeolocationPermissionsCallback`.
+   *
+   * <p>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.
+   *
+   * <p>See https://developer.android.com/reference/android/webkit/GeolocationPermissions.Callback.
+   *
+   * <p>Generated class from Pigeon that represents Flutter messages that can be called from Java.
+   */
+  public static class GeolocationPermissionsCallbackFlutterApi {
+    private final @NonNull BinaryMessenger binaryMessenger;
+
+    public GeolocationPermissionsCallbackFlutterApi(@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 GeolocationPermissionsCallbackFlutterApi. */
+    static @NonNull MessageCodec<Object> getCodec() {
+      return new StandardMessageCodec();
+    }
+    /** Create a new Dart instance and add it to the `InstanceManager`. */
+    public void create(@NonNull Long instanceIdArg, @NonNull Reply<Void> callback) {
+      BasicMessageChannel<Object> channel =
+          new BasicMessageChannel<>(
+              binaryMessenger,
+              "dev.flutter.pigeon.GeolocationPermissionsCallbackFlutterApi.create",
+              getCodec());
+      channel.send(
+          new ArrayList<Object>(Collections.singletonList(instanceIdArg)),
+          channelReply -> callback.reply(null));
+    }
+  }
 }
diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/GeolocationPermissionsCallbackFlutterApiImpl.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/GeolocationPermissionsCallbackFlutterApiImpl.java
new file mode 100644
index 0000000..32c66c0
--- /dev/null
+++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/GeolocationPermissionsCallbackFlutterApiImpl.java
@@ -0,0 +1,62 @@
+// 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.
+
+package io.flutter.plugins.webviewflutter;
+
+import android.webkit.GeolocationPermissions;
+import androidx.annotation.NonNull;
+import androidx.annotation.VisibleForTesting;
+import io.flutter.plugin.common.BinaryMessenger;
+import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.GeolocationPermissionsCallbackFlutterApi;
+
+/**
+ * Flutter API implementation for `GeolocationPermissionsCallback`.
+ *
+ * <p>This class may handle adding native instances that are attached to a Dart instance or passing
+ * arguments of callbacks methods to a Dart instance.
+ */
+public class GeolocationPermissionsCallbackFlutterApiImpl {
+  // To ease adding additional methods, this value is added prematurely.
+  @SuppressWarnings({"unused", "FieldCanBeLocal"})
+  private final BinaryMessenger binaryMessenger;
+
+  private final InstanceManager instanceManager;
+  private GeolocationPermissionsCallbackFlutterApi api;
+
+  /**
+   * Constructs a {@link GeolocationPermissionsCallbackFlutterApiImpl}.
+   *
+   * @param binaryMessenger used to communicate with Dart over asynchronous messages
+   * @param instanceManager maintains instances stored to communicate with attached Dart objects
+   */
+  public GeolocationPermissionsCallbackFlutterApiImpl(
+      @NonNull BinaryMessenger binaryMessenger, @NonNull InstanceManager instanceManager) {
+    this.binaryMessenger = binaryMessenger;
+    this.instanceManager = instanceManager;
+    api = new GeolocationPermissionsCallbackFlutterApi(binaryMessenger);
+  }
+
+  /**
+   * Stores the `GeolocationPermissionsCallback` instance and notifies Dart to create and store a
+   * new `GeolocationPermissionsCallback` instance that is attached to this one. If `instance` has
+   * already been added, this method does nothing.
+   */
+  public void create(
+      @NonNull GeolocationPermissions.Callback instance,
+      @NonNull GeolocationPermissionsCallbackFlutterApi.Reply<Void> callback) {
+    if (!instanceManager.containsInstance(instance)) {
+      api.create(instanceManager.addHostCreatedInstance(instance), callback);
+    }
+  }
+
+  /**
+   * Sets the Flutter API used to send messages to Dart.
+   *
+   * <p>This is only visible for testing.
+   */
+  @VisibleForTesting
+  void setApi(@NonNull GeolocationPermissionsCallbackFlutterApi api) {
+    this.api = api;
+  }
+}
diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/GeolocationPermissionsCallbackHostApiImpl.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/GeolocationPermissionsCallbackHostApiImpl.java
new file mode 100644
index 0000000..58981b6
--- /dev/null
+++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/GeolocationPermissionsCallbackHostApiImpl.java
@@ -0,0 +1,52 @@
+// 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.
+
+package io.flutter.plugins.webviewflutter;
+
+import android.webkit.GeolocationPermissions;
+import androidx.annotation.NonNull;
+import io.flutter.plugin.common.BinaryMessenger;
+import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.GeolocationPermissionsCallbackHostApi;
+import java.util.Objects;
+
+/**
+ * Host API implementation for `GeolocationPermissionsCallback`.
+ *
+ * <p>This class may handle instantiating and adding native object instances that are attached to a
+ * Dart instance or handle method calls on the associated native class or an instance of the class.
+ */
+public class GeolocationPermissionsCallbackHostApiImpl
+    implements GeolocationPermissionsCallbackHostApi {
+  // To ease adding additional methods, this value is added prematurely.
+  @SuppressWarnings({"unused", "FieldCanBeLocal"})
+  private final BinaryMessenger binaryMessenger;
+
+  private final InstanceManager instanceManager;
+
+  /**
+   * Constructs a {@link GeolocationPermissionsCallbackHostApiImpl}.
+   *
+   * @param binaryMessenger used to communicate with Dart over asynchronous messages
+   * @param instanceManager maintains instances stored to communicate with attached Dart objects
+   */
+  public GeolocationPermissionsCallbackHostApiImpl(
+      @NonNull BinaryMessenger binaryMessenger, @NonNull InstanceManager instanceManager) {
+    this.binaryMessenger = binaryMessenger;
+    this.instanceManager = instanceManager;
+  }
+
+  @Override
+  public void invoke(
+      @NonNull Long instanceId,
+      @NonNull String origin,
+      @NonNull Boolean allow,
+      @NonNull Boolean retain) {
+    getGeolocationPermissionsCallbackInstance(instanceId).invoke(origin, allow, retain);
+  }
+
+  private GeolocationPermissions.Callback getGeolocationPermissionsCallbackInstance(
+      @NonNull Long identifier) {
+    return Objects.requireNonNull(instanceManager.getInstance(identifier));
+  }
+}
diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebChromeClientFlutterApiImpl.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebChromeClientFlutterApiImpl.java
index fab34fc..ad5168f 100644
--- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebChromeClientFlutterApiImpl.java
+++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebChromeClientFlutterApiImpl.java
@@ -5,6 +5,7 @@
 package io.flutter.plugins.webviewflutter;
 
 import android.os.Build;
+import android.webkit.GeolocationPermissions;
 import android.webkit.PermissionRequest;
 import android.webkit.WebChromeClient;
 import android.webkit.WebView;
@@ -72,6 +73,32 @@
         callback);
   }
 
+  /** Passes arguments from {@link WebChromeClient#onGeolocationPermissionsShowPrompt} to Dart. */
+  public void onGeolocationPermissionsShowPrompt(
+      @NonNull WebChromeClient webChromeClient,
+      @NonNull String origin,
+      @NonNull GeolocationPermissions.Callback callback,
+      @NonNull WebChromeClientFlutterApi.Reply<Void> replyCallback) {
+    new GeolocationPermissionsCallbackFlutterApiImpl(binaryMessenger, instanceManager)
+        .create(callback, reply -> {});
+    onGeolocationPermissionsShowPrompt(
+        Objects.requireNonNull(instanceManager.getIdentifierForStrongReference(webChromeClient)),
+        Objects.requireNonNull(instanceManager.getIdentifierForStrongReference(callback)),
+        origin,
+        replyCallback);
+  }
+
+  /**
+   * Sends a message to Dart to call `WebChromeClient.onGeolocationPermissionsHidePrompt` on the
+   * Dart object representing `instance`.
+   */
+  public void onGeolocationPermissionsHidePrompt(
+      @NonNull WebChromeClient instance, @NonNull WebChromeClientFlutterApi.Reply<Void> callback) {
+    super.onGeolocationPermissionsHidePrompt(
+        Objects.requireNonNull(instanceManager.getIdentifierForStrongReference(instance)),
+        callback);
+  }
+
   /**
    * Sends a message to Dart to call `WebChromeClient.onPermissionRequest` on the Dart object
    * representing `instance`.
diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebChromeClientHostApiImpl.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebChromeClientHostApiImpl.java
index 38ebcb8..74ea45e 100644
--- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebChromeClientHostApiImpl.java
+++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebChromeClientHostApiImpl.java
@@ -7,6 +7,7 @@
 import android.net.Uri;
 import android.os.Build;
 import android.os.Message;
+import android.webkit.GeolocationPermissions;
 import android.webkit.PermissionRequest;
 import android.webkit.ValueCallback;
 import android.webkit.WebChromeClient;
@@ -51,6 +52,17 @@
       flutterApi.onProgressChanged(this, view, (long) progress, reply -> {});
     }
 
+    @Override
+    public void onGeolocationPermissionsShowPrompt(
+        @NonNull String origin, @NonNull GeolocationPermissions.Callback callback) {
+      flutterApi.onGeolocationPermissionsShowPrompt(this, origin, callback, reply -> {});
+    }
+
+    @Override
+    public void onGeolocationPermissionsHidePrompt() {
+      flutterApi.onGeolocationPermissionsHidePrompt(this, reply -> {});
+    }
+
     @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
     @SuppressWarnings("LambdaLast")
     @Override
diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewFlutterPlugin.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewFlutterPlugin.java
index 79640b9..3058219 100644
--- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewFlutterPlugin.java
+++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewFlutterPlugin.java
@@ -17,6 +17,7 @@
 import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.CookieManagerHostApi;
 import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.DownloadListenerHostApi;
 import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.FlutterAssetManagerHostApi;
+import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.GeolocationPermissionsCallbackHostApi;
 import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.InstanceManagerHostApi;
 import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.JavaObjectHostApi;
 import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.JavaScriptChannelHostApi;
@@ -137,6 +138,9 @@
       PermissionRequestHostApi.setup(
           binaryMessenger, new PermissionRequestHostApiImpl(binaryMessenger, instanceManager));
     }
+    GeolocationPermissionsCallbackHostApi.setup(
+        binaryMessenger,
+        new GeolocationPermissionsCallbackHostApiImpl(binaryMessenger, instanceManager));
   }
 
   @Override
diff --git a/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/GeolocationPermissionsCallbackTest.java b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/GeolocationPermissionsCallbackTest.java
new file mode 100644
index 0000000..14f8e15
--- /dev/null
+++ b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/GeolocationPermissionsCallbackTest.java
@@ -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.
+
+package io.flutter.plugins.webviewflutter;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.verify;
+
+import android.webkit.GeolocationPermissions;
+import io.flutter.plugin.common.BinaryMessenger;
+import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.GeolocationPermissionsCallbackFlutterApi;
+import java.util.Objects;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+public class GeolocationPermissionsCallbackTest {
+  @Rule public MockitoRule mockitoRule = MockitoJUnit.rule();
+
+  @Mock public GeolocationPermissions.Callback mockGeolocationPermissionsCallback;
+
+  @Mock public BinaryMessenger mockBinaryMessenger;
+
+  @Mock public GeolocationPermissionsCallbackFlutterApi mockFlutterApi;
+
+  InstanceManager instanceManager;
+
+  @Before
+  public void setUp() {
+    instanceManager = InstanceManager.create(identifier -> {});
+  }
+
+  @After
+  public void tearDown() {
+    instanceManager.stopFinalizationListener();
+  }
+
+  @Test
+  public void invoke() {
+    final String origin = "testString";
+    final boolean allow = true;
+    final boolean retain = true;
+
+    final long instanceIdentifier = 0;
+    instanceManager.addDartCreatedInstance(mockGeolocationPermissionsCallback, instanceIdentifier);
+
+    final GeolocationPermissionsCallbackHostApiImpl hostApi =
+        new GeolocationPermissionsCallbackHostApiImpl(mockBinaryMessenger, instanceManager);
+
+    hostApi.invoke(instanceIdentifier, origin, allow, retain);
+
+    verify(mockGeolocationPermissionsCallback).invoke(origin, allow, retain);
+  }
+
+  @Test
+  public void flutterApiCreate() {
+    final GeolocationPermissionsCallbackFlutterApiImpl flutterApi =
+        new GeolocationPermissionsCallbackFlutterApiImpl(mockBinaryMessenger, instanceManager);
+    flutterApi.setApi(mockFlutterApi);
+
+    flutterApi.create(mockGeolocationPermissionsCallback, reply -> {});
+
+    final long instanceIdentifier =
+        Objects.requireNonNull(
+            instanceManager.getIdentifierForStrongReference(mockGeolocationPermissionsCallback));
+    verify(mockFlutterApi).create(eq(instanceIdentifier), any());
+  }
+}
diff --git a/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebChromeClientTest.java b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebChromeClientTest.java
index 9a97cd6..e2d5a44 100644
--- a/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebChromeClientTest.java
+++ b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebChromeClientTest.java
@@ -15,6 +15,7 @@
 
 import android.net.Uri;
 import android.os.Message;
+import android.webkit.GeolocationPermissions;
 import android.webkit.PermissionRequest;
 import android.webkit.WebResourceRequest;
 import android.webkit.WebView;
@@ -120,9 +121,24 @@
   public void onPermissionRequest() {
     final PermissionRequest mockRequest = mock(PermissionRequest.class);
     instanceManager.addDartCreatedInstance(mockRequest, 10);
-
     webChromeClient.onPermissionRequest(mockRequest);
-
     verify(mockFlutterApi).onPermissionRequest(eq(webChromeClient), eq(mockRequest), any());
   }
+
+  @Test
+  public void onGeolocationPermissionsShowPrompt() {
+    final GeolocationPermissions.Callback mockCallback =
+        mock(GeolocationPermissions.Callback.class);
+    webChromeClient.onGeolocationPermissionsShowPrompt("https://flutter.dev", mockCallback);
+
+    verify(mockFlutterApi)
+        .onGeolocationPermissionsShowPrompt(
+            eq(webChromeClient), eq("https://flutter.dev"), eq(mockCallback), any());
+  }
+
+  @Test
+  public void onGeolocationPermissionsHidePrompt() {
+    webChromeClient.onGeolocationPermissionsHidePrompt();
+    verify(mockFlutterApi).onGeolocationPermissionsHidePrompt(eq(webChromeClient), any());
+  }
 }
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 6cbb932..e95de8c 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
@@ -28,18 +28,22 @@
   final android_webview.WebView Function() createAndroidWebView;
 
   /// Constructs a [android_webview.WebChromeClient].
-  final android_webview.WebChromeClient Function({
-    void Function(android_webview.WebView webView, int progress)?
-        onProgressChanged,
-    Future<List<String>> Function(
-      android_webview.WebView webView,
-      android_webview.FileChooserParams params,
-    )? onShowFileChooser,
-    void Function(
-      android_webview.WebChromeClient instance,
-      android_webview.PermissionRequest request,
-    )? onPermissionRequest,
-  }) createAndroidWebChromeClient;
+  final android_webview.WebChromeClient Function(
+      {void Function(android_webview.WebView webView, int progress)?
+          onProgressChanged,
+      Future<List<String>> Function(
+        android_webview.WebView webView,
+        android_webview.FileChooserParams params,
+      )? onShowFileChooser,
+      void Function(
+        android_webview.WebChromeClient instance,
+        android_webview.PermissionRequest request,
+      )? onPermissionRequest,
+      Future<void> Function(String origin,
+              android_webview.GeolocationPermissionsCallback callback)?
+          onGeolocationPermissionsShowPrompt,
+      void Function(android_webview.WebChromeClient instance)?
+          onGeolocationPermissionsHidePrompt}) createAndroidWebChromeClient;
 
   /// Constructs a [android_webview.WebViewClient].
   final android_webview.WebViewClient Function({
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 85d0ea0..85ec6b9 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
@@ -59,6 +59,57 @@
   }
 }
 
+/// A callback interface used by the host application to set the Geolocation
+/// permission state for an origin.
+///
+/// See https://developer.android.com/reference/android/webkit/GeolocationPermissions.Callback.
+@immutable
+class GeolocationPermissionsCallback extends JavaObject {
+  /// Instantiates a [GeolocationPermissionsCallback] 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.
+  @protected
+  GeolocationPermissionsCallback.detached({
+    super.binaryMessenger,
+    super.instanceManager,
+  })  : _geolocationPermissionsCallbackApi =
+            GeolocationPermissionsCallbackHostApiImpl(
+          binaryMessenger: binaryMessenger,
+          instanceManager: instanceManager,
+        ),
+        super.detached();
+
+  final GeolocationPermissionsCallbackHostApiImpl
+      _geolocationPermissionsCallbackApi;
+
+  /// Sets the Geolocation permission state for the supplied origin.
+  ///
+  /// [origin]: The origin for which permissions are set.
+  ///
+  /// [allow]: Whether or not the origin should be allowed to use the Geolocation API.
+  ///
+  /// [retain]: Whether the permission should be retained beyond the lifetime of
+  /// a page currently being displayed by a WebView.
+  Future<void> invoke(String origin, bool allow, bool retain) {
+    return _geolocationPermissionsCallbackApi.invokeFromInstances(
+      this,
+      origin,
+      allow,
+      retain,
+    );
+  }
+
+  @override
+  GeolocationPermissionsCallback copy() {
+    return GeolocationPermissionsCallback.detached(
+      binaryMessenger: _geolocationPermissionsCallbackApi.binaryMessenger,
+      instanceManager: _geolocationPermissionsCallbackApi.instanceManager,
+    );
+  }
+}
+
 /// An Android View that displays web pages.
 ///
 /// **Basic usage**
@@ -962,6 +1013,17 @@
   }
 }
 
+/// Responsible for request the Geolocation API.
+typedef GeolocationPermissionsShowPrompt = Future<void> Function(
+  String origin,
+  GeolocationPermissionsCallback callback,
+);
+
+/// Responsible for request the Geolocation API is Cancel.
+typedef GeolocationPermissionsHidePrompt = void Function(
+  WebChromeClient instance,
+);
+
 /// Handles JavaScript dialogs, favicons, titles, and the progress for [WebView].
 class WebChromeClient extends JavaObject {
   /// Constructs a [WebChromeClient].
@@ -969,6 +1031,8 @@
     this.onProgressChanged,
     this.onShowFileChooser,
     this.onPermissionRequest,
+    this.onGeolocationPermissionsShowPrompt,
+    this.onGeolocationPermissionsHidePrompt,
     @visibleForTesting super.binaryMessenger,
     @visibleForTesting super.instanceManager,
   }) : super.detached() {
@@ -986,6 +1050,8 @@
     this.onProgressChanged,
     this.onShowFileChooser,
     this.onPermissionRequest,
+    this.onGeolocationPermissionsShowPrompt,
+    this.onGeolocationPermissionsHidePrompt,
     super.binaryMessenger,
     super.instanceManager,
   }) : super.detached();
@@ -1020,6 +1086,16 @@
     PermissionRequest request,
   )? onPermissionRequest;
 
+  /// Indicates the client should handle geolocation permissions.
+  final GeolocationPermissionsShowPrompt? onGeolocationPermissionsShowPrompt;
+
+  /// Notify the host application that a request for Geolocation permissions,
+  /// made with a previous call to [onGeolocationPermissionsShowPrompt] has been
+  /// canceled.
+  final void Function(
+    WebChromeClient instance,
+  )? onGeolocationPermissionsHidePrompt;
+
   /// Sets the required synchronous return value for the Java method,
   /// `WebChromeClient.onShowFileChooser(...)`.
   ///
@@ -1054,6 +1130,8 @@
     return WebChromeClient.detached(
       onProgressChanged: onProgressChanged,
       onShowFileChooser: onShowFileChooser,
+      onGeolocationPermissionsShowPrompt: onGeolocationPermissionsShowPrompt,
+      onGeolocationPermissionsHidePrompt: onGeolocationPermissionsHidePrompt,
       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 5a2c56e..70473bf 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
@@ -377,6 +377,7 @@
 
 class _WebViewHostApiCodec extends StandardMessageCodec {
   const _WebViewHostApiCodec();
+
   @override
   void writeValue(WriteBuffer buffer, Object? value) {
     if (value is WebViewPoint) {
@@ -1528,6 +1529,7 @@
 
 class _WebViewClientFlutterApiCodec extends StandardMessageCodec {
   const _WebViewClientFlutterApiCodec();
+
   @override
   void writeValue(WriteBuffer buffer, Object? value) {
     if (value is WebResourceErrorData) {
@@ -1990,6 +1992,13 @@
   /// Callback to Dart function `WebChromeClient.onPermissionRequest`.
   void onPermissionRequest(int instanceId, int requestInstanceId);
 
+  /// Callback to Dart function `WebChromeClient.onGeolocationPermissionsShowPrompt`.
+  void onGeolocationPermissionsShowPrompt(
+      int instanceId, int paramsInstanceId, String origin);
+
+  /// Callback to Dart function `WebChromeClient.onGeolocationPermissionsHidePrompt`.
+  void onGeolocationPermissionsHidePrompt(int identifier);
+
   static void setup(WebChromeClientFlutterApi? api,
       {BinaryMessenger? binaryMessenger}) {
     {
@@ -2069,6 +2078,53 @@
         });
       }
     }
+    {
+      final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
+          'dev.flutter.pigeon.WebChromeClientFlutterApi.onGeolocationPermissionsShowPrompt',
+          codec,
+          binaryMessenger: binaryMessenger);
+      if (api == null) {
+        channel.setMessageHandler(null);
+      } else {
+        channel.setMessageHandler((Object? message) async {
+          assert(message != null,
+              'Argument for dev.flutter.pigeon.WebChromeClientFlutterApi.onGeolocationPermissionsShowPrompt 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.WebChromeClientFlutterApi.onGeolocationPermissionsShowPrompt was null, expected non-null int.');
+          final int? arg_paramsInstanceId = (args[1] as int?);
+          assert(arg_paramsInstanceId != null,
+              'Argument for dev.flutter.pigeon.WebChromeClientFlutterApi.onGeolocationPermissionsShowPrompt was null, expected non-null int.');
+          final String? arg_origin = (args[2] as String?);
+          assert(arg_origin != null,
+              'Argument for dev.flutter.pigeon.WebChromeClientFlutterApi.onGeolocationPermissionsShowPrompt was null, expected non-null String.');
+          api.onGeolocationPermissionsShowPrompt(
+              arg_instanceId!, arg_paramsInstanceId!, arg_origin!);
+          return;
+        });
+      }
+    }
+    {
+      final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
+          'dev.flutter.pigeon.WebChromeClientFlutterApi.onGeolocationPermissionsHidePrompt',
+          codec,
+          binaryMessenger: binaryMessenger);
+      if (api == null) {
+        channel.setMessageHandler(null);
+      } else {
+        channel.setMessageHandler((Object? message) async {
+          assert(message != null,
+              'Argument for dev.flutter.pigeon.WebChromeClientFlutterApi.onGeolocationPermissionsHidePrompt 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.WebChromeClientFlutterApi.onGeolocationPermissionsHidePrompt was null, expected non-null int.');
+          api.onGeolocationPermissionsHidePrompt(arg_identifier!);
+          return;
+        });
+      }
+    }
   }
 }
 
@@ -2129,6 +2185,7 @@
 
 class _FileChooserParamsFlutterApiCodec extends StandardMessageCodec {
   const _FileChooserParamsFlutterApiCodec();
+
   @override
   void writeValue(WriteBuffer buffer, Object? value) {
     if (value is FileChooserModeEnumData) {
@@ -2301,3 +2358,85 @@
     }
   }
 }
+
+/// Host API for `GeolocationPermissionsCallback`.
+///
+/// This class may handle instantiating and adding native object instances that
+/// are attached to a Dart instance or handle method calls on the associated
+/// native class or an instance of the class.
+///
+/// See https://developer.android.com/reference/android/webkit/GeolocationPermissions.Callback.
+class GeolocationPermissionsCallbackHostApi {
+  /// Constructor for [GeolocationPermissionsCallbackHostApi].  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.
+  GeolocationPermissionsCallbackHostApi({BinaryMessenger? binaryMessenger})
+      : _binaryMessenger = binaryMessenger;
+  final BinaryMessenger? _binaryMessenger;
+
+  static const MessageCodec<Object?> codec = StandardMessageCodec();
+
+  /// Handles Dart method `GeolocationPermissionsCallback.invoke`.
+  Future<void> invoke(int arg_instanceId, String arg_origin, bool arg_allow,
+      bool arg_retain) async {
+    final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
+        'dev.flutter.pigeon.GeolocationPermissionsCallbackHostApi.invoke',
+        codec,
+        binaryMessenger: _binaryMessenger);
+    final List<Object?>? replyList = await channel
+            .send(<Object?>[arg_instanceId, arg_origin, arg_allow, arg_retain])
+        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;
+    }
+  }
+}
+
+/// Flutter API for `GeolocationPermissionsCallback`.
+///
+/// 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.android.com/reference/android/webkit/GeolocationPermissions.Callback.
+abstract class GeolocationPermissionsCallbackFlutterApi {
+  static const MessageCodec<Object?> codec = StandardMessageCodec();
+
+  /// Create a new Dart instance and add it to the `InstanceManager`.
+  void create(int instanceId);
+
+  static void setup(GeolocationPermissionsCallbackFlutterApi? api,
+      {BinaryMessenger? binaryMessenger}) {
+    {
+      final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
+          'dev.flutter.pigeon.GeolocationPermissionsCallbackFlutterApi.create',
+          codec,
+          binaryMessenger: binaryMessenger);
+      if (api == null) {
+        channel.setMessageHandler(null);
+      } else {
+        channel.setMessageHandler((Object? message) async {
+          assert(message != null,
+              'Argument for dev.flutter.pigeon.GeolocationPermissionsCallbackFlutterApi.create 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.GeolocationPermissionsCallbackFlutterApi.create was null, expected non-null int.');
+          api.create(arg_instanceId!);
+          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 7f7c342..3f8e10b 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
@@ -45,6 +45,8 @@
     WebChromeClientFlutterApiImpl? webChromeClientFlutterApi,
     JavaScriptChannelFlutterApiImpl? javaScriptChannelFlutterApi,
     FileChooserParamsFlutterApiImpl? fileChooserParamsFlutterApi,
+    GeolocationPermissionsCallbackFlutterApiImpl?
+        geolocationPermissionsCallbackFlutterApi,
     WebViewFlutterApiImpl? webViewFlutterApi,
     PermissionRequestFlutterApiImpl? permissionRequestFlutterApi,
   }) {
@@ -60,6 +62,9 @@
         javaScriptChannelFlutterApi ?? JavaScriptChannelFlutterApiImpl();
     this.fileChooserParamsFlutterApi =
         fileChooserParamsFlutterApi ?? FileChooserParamsFlutterApiImpl();
+    this.geolocationPermissionsCallbackFlutterApi =
+        geolocationPermissionsCallbackFlutterApi ??
+            GeolocationPermissionsCallbackFlutterApiImpl();
     this.webViewFlutterApi = webViewFlutterApi ?? WebViewFlutterApiImpl();
     this.permissionRequestFlutterApi =
         permissionRequestFlutterApi ?? PermissionRequestFlutterApiImpl();
@@ -90,6 +95,10 @@
   /// Flutter Api for [FileChooserParams].
   late final FileChooserParamsFlutterApiImpl fileChooserParamsFlutterApi;
 
+  /// Flutter Api for [GeolocationPermissionsCallback].
+  late final GeolocationPermissionsCallbackFlutterApiImpl
+      geolocationPermissionsCallbackFlutterApi;
+
   /// Flutter Api for [WebView].
   late final WebViewFlutterApiImpl webViewFlutterApi;
 
@@ -105,6 +114,8 @@
       WebChromeClientFlutterApi.setup(webChromeClientFlutterApi);
       JavaScriptChannelFlutterApi.setup(javaScriptChannelFlutterApi);
       FileChooserParamsFlutterApi.setup(fileChooserParamsFlutterApi);
+      GeolocationPermissionsCallbackFlutterApi.setup(
+          geolocationPermissionsCallbackFlutterApi);
       WebViewFlutterApi.setup(webViewFlutterApi);
       PermissionRequestFlutterApi.setup(permissionRequestFlutterApi);
       _haveBeenSetUp = true;
@@ -921,6 +932,32 @@
   }
 
   @override
+  void onGeolocationPermissionsShowPrompt(
+      int instanceId, int paramsInstanceId, String origin) {
+    final WebChromeClient instance =
+        instanceManager.getInstanceWithWeakReference(instanceId)!;
+    final GeolocationPermissionsCallback callback =
+        instanceManager.getInstanceWithWeakReference(paramsInstanceId)!
+            as GeolocationPermissionsCallback;
+    final GeolocationPermissionsShowPrompt? onShowPrompt =
+        instance.onGeolocationPermissionsShowPrompt;
+    if (onShowPrompt != null) {
+      onShowPrompt(origin, callback);
+    }
+  }
+
+  @override
+  void onGeolocationPermissionsHidePrompt(int identifier) {
+    final WebChromeClient instance =
+        instanceManager.getInstanceWithWeakReference(identifier)!;
+    final GeolocationPermissionsHidePrompt? onHidePrompt =
+        instance.onGeolocationPermissionsHidePrompt;
+    if (onHidePrompt != null) {
+      return onHidePrompt(instance);
+    }
+  }
+
+  @override
   void onPermissionRequest(
     int instanceId,
     int requestInstanceId,
@@ -1007,6 +1044,75 @@
   }
 }
 
+/// Host api implementation for [GeolocationPermissionsCallback].
+class GeolocationPermissionsCallbackHostApiImpl
+    extends GeolocationPermissionsCallbackHostApi {
+  /// Constructs a [GeolocationPermissionsCallbackHostApiImpl].
+  GeolocationPermissionsCallbackHostApiImpl({
+    this.binaryMessenger,
+    InstanceManager? instanceManager,
+  })  : instanceManager = instanceManager ?? JavaObject.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 java objects.
+  final InstanceManager instanceManager;
+
+  /// Helper method to convert instances ids to objects.
+  Future<void> invokeFromInstances(
+    GeolocationPermissionsCallback instance,
+    String origin,
+    bool allow,
+    bool retain,
+  ) {
+    return invoke(
+      instanceManager.getIdentifier(instance)!,
+      origin,
+      allow,
+      retain,
+    );
+  }
+}
+
+/// Flutter API implementation for [GeolocationPermissionsCallback].
+///
+/// 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 GeolocationPermissionsCallbackFlutterApiImpl
+    implements GeolocationPermissionsCallbackFlutterApi {
+  /// Constructs a [GeolocationPermissionsCallbackFlutterApiImpl].
+  GeolocationPermissionsCallbackFlutterApiImpl({
+    this.binaryMessenger,
+    InstanceManager? instanceManager,
+  }) : instanceManager = instanceManager ?? JavaObject.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 instanceId) {
+    instanceManager.addHostCreatedInstance(
+      GeolocationPermissionsCallback.detached(
+        binaryMessenger: binaryMessenger,
+        instanceManager: instanceManager,
+      ),
+      instanceId,
+    );
+  }
+}
+
 /// Host api implementation for [PermissionRequest].
 class PermissionRequestHostApiImpl extends PermissionRequestHostApi {
   /// Constructs a [PermissionRequestHostApiImpl].
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 a6d3eac..151cc81 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
@@ -110,6 +110,33 @@
         }
       };
     }),
+    onGeolocationPermissionsShowPrompt: withWeakReferenceTo(this,
+        (WeakReference<AndroidWebViewController> weakReference) {
+      return (String origin,
+          android_webview.GeolocationPermissionsCallback callback) async {
+        final OnGeolocationPermissionsShowPrompt? onShowPrompt =
+            weakReference.target?._onGeolocationPermissionsShowPrompt;
+        if (onShowPrompt != null) {
+          final GeolocationPermissionsResponse response = await onShowPrompt(
+            GeolocationPermissionsRequestParams(origin: origin),
+          );
+          callback.invoke(origin, response.allow, response.retain);
+        } else {
+          // default don't allow
+          callback.invoke(origin, false, false);
+        }
+      };
+    }),
+    onGeolocationPermissionsHidePrompt: withWeakReferenceTo(this,
+        (WeakReference<AndroidWebViewController> weakReference) {
+      return (android_webview.WebChromeClient instance) {
+        final OnGeolocationPermissionsHidePrompt? onHidePrompt =
+            weakReference.target?._onGeolocationPermissionsHidePrompt;
+        if (onHidePrompt != null) {
+          onHidePrompt();
+        }
+      };
+    }),
     onShowFileChooser: withWeakReferenceTo(
       this,
       (WeakReference<AndroidWebViewController> weakReference) {
@@ -180,6 +207,11 @@
 
   Future<List<String>> Function(FileSelectorParams)?
       _onShowFileSelectorCallback;
+
+  OnGeolocationPermissionsShowPrompt? _onGeolocationPermissionsShowPrompt;
+
+  OnGeolocationPermissionsHidePrompt? _onGeolocationPermissionsHidePrompt;
+
   void Function(PlatformWebViewPermissionRequest)? _onPermissionRequestCallback;
 
   /// Whether to enable the platform's webview content debugging tools.
@@ -434,6 +466,33 @@
   ) async {
     _onPermissionRequestCallback = onPermissionRequest;
   }
+
+  /// Sets the callback that is invoked when the client request handle geolocation permissions.
+  ///
+  /// Param [onShowPrompt] notifies the host application that web content from the specified origin is attempting to use the Geolocation API,
+  /// but no permission state is currently set for that origin.
+  ///
+  /// The host application should invoke the specified callback with the desired permission state.
+  /// See GeolocationPermissions for details.
+  ///
+  /// Note that for applications targeting Android N and later SDKs (API level > Build.VERSION_CODES.M)
+  /// this method is only called for requests originating from secure origins such as https.
+  /// On non-secure origins geolocation requests are automatically denied.
+  ///
+  /// Param [onHidePrompt] notifies the host application that a request for Geolocation permissions,
+  /// made with a previous call to onGeolocationPermissionsShowPrompt() has been canceled.
+  /// Any related UI should therefore be hidden.
+  ///
+  /// See https://developer.android.com/reference/android/webkit/WebChromeClient#onGeolocationPermissionsShowPrompt(java.lang.String,%20android.webkit.GeolocationPermissions.Callback)
+  ///
+  /// See https://developer.android.com/reference/android/webkit/WebChromeClient#onGeolocationPermissionsHidePrompt()
+  Future<void> setGeolocationPermissionsPromptCallbacks({
+    OnGeolocationPermissionsShowPrompt? onShowPrompt,
+    OnGeolocationPermissionsHidePrompt? onHidePrompt,
+  }) async {
+    _onGeolocationPermissionsShowPrompt = onShowPrompt;
+    _onGeolocationPermissionsHidePrompt = onHidePrompt;
+  }
 }
 
 /// Android implementation of [PlatformWebViewPermissionRequest].
@@ -472,6 +531,46 @@
   }
 }
 
+/// Signature for the `setGeolocationPermissionsPromptCallbacks` callback responsible for request the Geolocation API.
+typedef OnGeolocationPermissionsShowPrompt
+    = Future<GeolocationPermissionsResponse> Function(
+        GeolocationPermissionsRequestParams request);
+
+/// Signature for the `setGeolocationPermissionsPromptCallbacks` callback responsible for request the Geolocation API is cancel.
+typedef OnGeolocationPermissionsHidePrompt = void Function();
+
+/// A request params used by the host application to set the Geolocation permission state for an origin.
+@immutable
+class GeolocationPermissionsRequestParams {
+  /// [origin]: The origin for which permissions are set.
+  const GeolocationPermissionsRequestParams({
+    required this.origin,
+  });
+
+  /// [origin]: The origin for which permissions are set.
+  final String origin;
+}
+
+/// A response used by the host application to set the Geolocation permission state for an origin.
+@immutable
+class GeolocationPermissionsResponse {
+  /// [allow]: Whether or not the origin should be allowed to use the Geolocation API.
+  ///
+  /// [retain]: Whether the permission should be retained beyond the lifetime of
+  /// a page currently being displayed by a WebView.
+  const GeolocationPermissionsResponse({
+    required this.allow,
+    required this.retain,
+  });
+
+  /// Whether or not the origin should be allowed to use the Geolocation API.
+  final bool allow;
+
+  /// Whether the permission should be retained beyond the lifetime of
+  /// a page currently being displayed by a WebView.
+  final bool retain;
+}
+
 /// Mode of how to select files for a file chooser.
 enum FileSelectorMode {
   /// Open single file and requires that the file exists before allowing the
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 a4886b9..f75eb32 100644
--- a/packages/webview_flutter/webview_flutter_android/pigeons/android_webview.dart
+++ b/packages/webview_flutter/webview_flutter_android/pigeons/android_webview.dart
@@ -365,6 +365,16 @@
 
   /// Callback to Dart function `WebChromeClient.onPermissionRequest`.
   void onPermissionRequest(int instanceId, int requestInstanceId);
+
+  /// Callback to Dart function `WebChromeClient.onGeolocationPermissionsShowPrompt`.
+  void onGeolocationPermissionsShowPrompt(
+    int instanceId,
+    int paramsInstanceId,
+    String origin,
+  );
+
+  /// Callback to Dart function `WebChromeClient.onGeolocationPermissionsHidePrompt`.
+  void onGeolocationPermissionsHidePrompt(int identifier);
 }
 
 @HostApi(dartHostTestHandler: 'TestWebStorageHostApi')
@@ -416,3 +426,29 @@
   /// Create a new Dart instance and add it to the `InstanceManager`.
   void create(int instanceId, List<String> resources);
 }
+
+/// Host API for `GeolocationPermissionsCallback`.
+///
+/// This class may handle instantiating and adding native object instances that
+/// are attached to a Dart instance or handle method calls on the associated
+/// native class or an instance of the class.
+///
+/// See https://developer.android.com/reference/android/webkit/GeolocationPermissions.Callback.
+@HostApi(dartHostTestHandler: 'TestGeolocationPermissionsCallbackHostApi')
+abstract class GeolocationPermissionsCallbackHostApi {
+  /// Handles Dart method `GeolocationPermissionsCallback.invoke`.
+  void invoke(int instanceId, String origin, bool allow, bool retain);
+}
+
+/// Flutter API for `GeolocationPermissionsCallback`.
+///
+/// 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.android.com/reference/android/webkit/GeolocationPermissions.Callback.
+@FlutterApi()
+abstract class GeolocationPermissionsCallbackFlutterApi {
+  /// Create a new Dart instance and add it to the `InstanceManager`.
+  void create(int instanceId);
+}
diff --git a/packages/webview_flutter/webview_flutter_android/pubspec.yaml b/packages/webview_flutter/webview_flutter_android/pubspec.yaml
index fb17376..189843e 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.7.1
+version: 3.8.0
 
 environment:
   sdk: ">=2.18.0 <4.0.0"
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 7d834ba..3f93d46 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
@@ -515,6 +515,8 @@
   CapturingWebChromeClient({
     super.onProgressChanged,
     super.onShowFileChooser,
+    super.onGeolocationPermissionsShowPrompt,
+    super.onGeolocationPermissionsHidePrompt,
     super.onPermissionRequest,
     super.binaryMessenger,
     super.instanceManager,
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 8dcc1ad..d8527ca 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
@@ -18,6 +18,8 @@
 
 import 'android_navigation_delegate_test.dart';
 import 'android_webview_controller_test.mocks.dart';
+import 'android_webview_test.mocks.dart'
+    show MockTestGeolocationPermissionsCallbackHostApi;
 import 'test_android_webview.g.dart';
 
 @GenerateNiceMocks(<MockSpec<Object>>[
@@ -55,6 +57,10 @@
         android_webview.WebView webView,
         android_webview.FileChooserParams params,
       )? onShowFileChooser,
+      android_webview.GeolocationPermissionsShowPrompt?
+          onGeolocationPermissionsShowPrompt,
+      android_webview.GeolocationPermissionsHidePrompt?
+          onGeolocationPermissionsHidePrompt,
       void Function(
         android_webview.WebChromeClient instance,
         android_webview.PermissionRequest request,
@@ -73,18 +79,25 @@
             androidWebStorage: mockWebStorage ?? MockWebStorage(),
             androidWebViewProxy: AndroidWebViewProxy(
               createAndroidWebChromeClient: createWebChromeClient ??
-                  ({
-                    void Function(android_webview.WebView, int)?
-                        onProgressChanged,
-                    Future<List<String>> Function(
-                      android_webview.WebView webView,
-                      android_webview.FileChooserParams params,
-                    )? onShowFileChooser,
-                    void Function(
-                      android_webview.WebChromeClient instance,
-                      android_webview.PermissionRequest request,
-                    )? onPermissionRequest,
-                  }) =>
+                  (
+                          {void Function(android_webview.WebView, int)?
+                              onProgressChanged,
+                          Future<List<String>> Function(
+                            android_webview.WebView webView,
+                            android_webview.FileChooserParams params,
+                          )? onShowFileChooser,
+                          void Function(
+                            android_webview.WebChromeClient instance,
+                            android_webview.PermissionRequest request,
+                          )? onPermissionRequest,
+                          Future<void> Function(
+                            String origin,
+                            android_webview.GeolocationPermissionsCallback
+                                callback,
+                          )? onGeolocationPermissionsShowPrompt,
+                          void Function(
+                                  android_webview.WebChromeClient instance)?
+                              onGeolocationPermissionsHidePrompt}) =>
                       MockWebChromeClient(),
               createAndroidWebView: () => nonNullMockWebView,
               createAndroidWebViewClient: ({
@@ -574,6 +587,8 @@
             android_webview.WebView webView,
             android_webview.FileChooserParams params,
           )? onShowFileChooser,
+          dynamic onGeolocationPermissionsShowPrompt,
+          dynamic onGeolocationPermissionsHidePrompt,
           dynamic onPermissionRequest,
         }) {
           onShowFileChooserCallback = onShowFileChooser!;
@@ -609,6 +624,75 @@
       expect(fileSelectorParams.mode, FileSelectorMode.open);
     });
 
+    test('setGeolocationPermissionsPromptCallbacks', () async {
+      final MockTestGeolocationPermissionsCallbackHostApi mockApi =
+          MockTestGeolocationPermissionsCallbackHostApi();
+      TestGeolocationPermissionsCallbackHostApi.setup(mockApi);
+
+      final InstanceManager instanceManager = InstanceManager(
+        onWeakReferenceRemoved: (_) {},
+      );
+
+      final android_webview.GeolocationPermissionsCallback testCallback =
+          android_webview.GeolocationPermissionsCallback.detached(
+        instanceManager: instanceManager,
+      );
+
+      const int instanceIdentifier = 0;
+      instanceManager.addHostCreatedInstance(testCallback, instanceIdentifier);
+
+      late final Future<void> Function(String origin,
+              android_webview.GeolocationPermissionsCallback callback)
+          onGeoPermissionHandle;
+      late final void Function(android_webview.WebChromeClient instance)
+          onGeoPermissionHidePromptHandle;
+
+      final MockWebChromeClient mockWebChromeClient = MockWebChromeClient();
+      final AndroidWebViewController controller = createControllerWithMocks(
+        createWebChromeClient: ({
+          dynamic onProgressChanged,
+          dynamic onShowFileChooser,
+          Future<void> Function(String origin,
+                  android_webview.GeolocationPermissionsCallback callback)?
+              onGeolocationPermissionsShowPrompt,
+          void Function(android_webview.WebChromeClient instance)?
+              onGeolocationPermissionsHidePrompt,
+          dynamic onPermissionRequest,
+        }) {
+          onGeoPermissionHandle = onGeolocationPermissionsShowPrompt!;
+          onGeoPermissionHidePromptHandle = onGeolocationPermissionsHidePrompt!;
+          return mockWebChromeClient;
+        },
+      );
+
+      String testValue = 'origin';
+      const String allowOrigin = 'https://www.allow.com';
+      bool isAllow = false;
+
+      late final GeolocationPermissionsResponse response;
+      controller.setGeolocationPermissionsPromptCallbacks(
+        onShowPrompt: (GeolocationPermissionsRequestParams request) async {
+          isAllow = request.origin == allowOrigin;
+          response =
+              GeolocationPermissionsResponse(allow: isAllow, retain: isAllow);
+          return response;
+        },
+        onHidePrompt: () {
+          testValue = 'changed';
+        },
+      );
+
+      await onGeoPermissionHandle(
+        allowOrigin,
+        testCallback,
+      );
+
+      expect(isAllow, true);
+
+      onGeoPermissionHidePromptHandle(mockWebChromeClient);
+      expect(testValue, 'changed');
+    });
+
     test('setOnPlatformPermissionRequest', () async {
       late final void Function(
         android_webview.WebChromeClient instance,
@@ -620,6 +704,8 @@
         createWebChromeClient: ({
           dynamic onProgressChanged,
           dynamic onShowFileChooser,
+          dynamic onGeolocationPermissionsShowPrompt,
+          dynamic onGeolocationPermissionsHidePrompt,
           void Function(
             android_webview.WebChromeClient instance,
             android_webview.PermissionRequest request,
@@ -670,6 +756,8 @@
         createWebChromeClient: ({
           dynamic onProgressChanged,
           dynamic onShowFileChooser,
+          dynamic onGeolocationPermissionsShowPrompt,
+          dynamic onGeolocationPermissionsHidePrompt,
           void Function(
             android_webview.WebChromeClient instance,
             android_webview.PermissionRequest request,
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 093312e..f6e7124 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
@@ -719,6 +719,23 @@
         returnValue: _i9.Future<void>.value(),
         returnValueForMissingStub: _i9.Future<void>.value(),
       ) as _i9.Future<void>);
+  @override
+  _i9.Future<void> setGeolocationPermissionsPromptCallbacks({
+    _i8.OnGeolocationPermissionsShowPrompt? onShowPrompt,
+    _i8.OnGeolocationPermissionsHidePrompt? onHidePrompt,
+  }) =>
+      (super.noSuchMethod(
+        Invocation.method(
+          #setGeolocationPermissionsPromptCallbacks,
+          [],
+          {
+            #onShowPrompt: onShowPrompt,
+            #onHidePrompt: onHidePrompt,
+          },
+        ),
+        returnValue: _i9.Future<void>.value(),
+        returnValueForMissingStub: _i9.Future<void>.value(),
+      ) as _i9.Future<void>);
 }
 
 /// A class which mocks [AndroidWebViewProxy].
@@ -740,6 +757,11 @@
       ) as _i2.WebView Function());
   @override
   _i2.WebChromeClient Function({
+    void Function(_i2.WebChromeClient)? onGeolocationPermissionsHidePrompt,
+    _i9.Future<void> Function(
+      String,
+      _i2.GeolocationPermissionsCallback,
+    )? onGeolocationPermissionsShowPrompt,
     void Function(
       _i2.WebChromeClient,
       _i2.PermissionRequest,
@@ -755,6 +777,12 @@
   }) get createAndroidWebChromeClient => (super.noSuchMethod(
         Invocation.getter(#createAndroidWebChromeClient),
         returnValue: ({
+          void Function(_i2.WebChromeClient)?
+              onGeolocationPermissionsHidePrompt,
+          _i9.Future<void> Function(
+            String,
+            _i2.GeolocationPermissionsCallback,
+          )? onGeolocationPermissionsShowPrompt,
           void Function(
             _i2.WebChromeClient,
             _i2.PermissionRequest,
@@ -773,6 +801,12 @@
           Invocation.getter(#createAndroidWebChromeClient),
         ),
         returnValueForMissingStub: ({
+          void Function(_i2.WebChromeClient)?
+              onGeolocationPermissionsHidePrompt,
+          _i9.Future<void> Function(
+            String,
+            _i2.GeolocationPermissionsCallback,
+          )? onGeolocationPermissionsShowPrompt,
           void Function(
             _i2.WebChromeClient,
             _i2.PermissionRequest,
@@ -791,6 +825,11 @@
           Invocation.getter(#createAndroidWebChromeClient),
         ),
       ) as _i2.WebChromeClient Function({
+        void Function(_i2.WebChromeClient)? onGeolocationPermissionsHidePrompt,
+        _i9.Future<void> Function(
+          String,
+          _i2.GeolocationPermissionsCallback,
+        )? onGeolocationPermissionsShowPrompt,
         void Function(
           _i2.WebChromeClient,
           _i2.PermissionRequest,
diff --git a/packages/webview_flutter/webview_flutter_android/test/android_webview_cookie_manager_test.mocks.dart b/packages/webview_flutter/webview_flutter_android/test/android_webview_cookie_manager_test.mocks.dart
index 9f4aa1d..ee0b481 100644
--- a/packages/webview_flutter/webview_flutter_android/test/android_webview_cookie_manager_test.mocks.dart
+++ b/packages/webview_flutter/webview_flutter_android/test/android_webview_cookie_manager_test.mocks.dart
@@ -454,6 +454,23 @@
         returnValue: _i5.Future<void>.value(),
         returnValueForMissingStub: _i5.Future<void>.value(),
       ) as _i5.Future<void>);
+  @override
+  _i5.Future<void> setGeolocationPermissionsPromptCallbacks({
+    _i6.OnGeolocationPermissionsShowPrompt? onShowPrompt,
+    _i6.OnGeolocationPermissionsHidePrompt? onHidePrompt,
+  }) =>
+      (super.noSuchMethod(
+        Invocation.method(
+          #setGeolocationPermissionsPromptCallbacks,
+          [],
+          {
+            #onShowPrompt: onShowPrompt,
+            #onHidePrompt: onHidePrompt,
+          },
+        ),
+        returnValue: _i5.Future<void>.value(),
+        returnValueForMissingStub: _i5.Future<void>.value(),
+      ) as _i5.Future<void>);
 }
 
 /// A class which mocks [TestInstanceManagerHostApi].
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 922d7c7..995694f 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
@@ -19,6 +19,7 @@
   JavaScriptChannel,
   TestCookieManagerHostApi,
   TestDownloadListenerHostApi,
+  TestGeolocationPermissionsCallbackHostApi,
   TestInstanceManagerHostApi,
   TestJavaObjectHostApi,
   TestJavaScriptChannelHostApi,
@@ -887,6 +888,28 @@
         expect(result, containsAllInOrder(<Object?>[mockWebView, 76]));
       });
 
+      test('onGeolocationPermissionsShowPrompt', () async {
+        const String origin = 'https://www.example.com';
+        final GeolocationPermissionsCallback callback =
+            GeolocationPermissionsCallback.detached();
+        final int paramsId = instanceManager.addDartCreatedInstance(callback);
+        late final GeolocationPermissionsCallback outerCallback;
+        when(mockWebChromeClient.onGeolocationPermissionsShowPrompt).thenReturn(
+          (String origin, GeolocationPermissionsCallback callback) async {
+            outerCallback = callback;
+          },
+        );
+        flutterApi.onGeolocationPermissionsShowPrompt(
+          mockWebChromeClientInstanceId,
+          paramsId,
+          origin,
+        );
+        await expectLater(
+          outerCallback,
+          callback,
+        );
+      });
+
       test('onShowFileChooser', () async {
         late final List<Object> result;
         when(mockWebChromeClient.onShowFileChooser).thenReturn(
@@ -1019,32 +1042,59 @@
       });
     });
 
-    group('FileChooserParams', () {
-      test('FlutterApi create', () {
-        final InstanceManager instanceManager = InstanceManager(
-          onWeakReferenceRemoved: (_) {},
-        );
+    test('onGeolocationPermissionsHidePrompt', () {
+      final InstanceManager instanceManager = InstanceManager(
+        onWeakReferenceRemoved: (_) {},
+      );
 
-        final FileChooserParamsFlutterApiImpl flutterApi =
-            FileChooserParamsFlutterApiImpl(
-          instanceManager: instanceManager,
-        );
+      const int instanceIdentifier = 0;
+      late final List<Object?> callbackParameters;
+      final WebChromeClient instance = WebChromeClient.detached(
+        onGeolocationPermissionsHidePrompt: (WebChromeClient instance) {
+          callbackParameters = <Object?>[instance];
+        },
+        instanceManager: instanceManager,
+      );
+      instanceManager.addHostCreatedInstance(instance, instanceIdentifier);
 
-        flutterApi.create(
-          0,
-          false,
-          const <String>['my', 'list'],
-          FileChooserModeEnumData(value: FileChooserMode.openMultiple),
-          'filenameHint',
-        );
+      final WebChromeClientFlutterApiImpl flutterApi =
+          WebChromeClientFlutterApiImpl(instanceManager: instanceManager);
 
-        final FileChooserParams instance = instanceManager
-            .getInstanceWithWeakReference(0)! as FileChooserParams;
-        expect(instance.isCaptureEnabled, false);
-        expect(instance.acceptTypes, const <String>['my', 'list']);
-        expect(instance.mode, FileChooserMode.openMultiple);
-        expect(instance.filenameHint, 'filenameHint');
-      });
+      flutterApi.onGeolocationPermissionsHidePrompt(instanceIdentifier);
+
+      expect(callbackParameters, <Object?>[instance]);
+    });
+
+    test('copy', () {
+      expect(WebChromeClient.detached().copy(), isA<WebChromeClient>());
+    });
+  });
+
+  group('FileChooserParams', () {
+    test('FlutterApi create', () {
+      final InstanceManager instanceManager = InstanceManager(
+        onWeakReferenceRemoved: (_) {},
+      );
+
+      final FileChooserParamsFlutterApiImpl flutterApi =
+          FileChooserParamsFlutterApiImpl(
+        instanceManager: instanceManager,
+      );
+
+      flutterApi.create(
+        0,
+        false,
+        const <String>['my', 'list'],
+        FileChooserModeEnumData(value: FileChooserMode.openMultiple),
+        'filenameHint',
+      );
+
+      final FileChooserParams instance =
+          instanceManager.getInstanceWithWeakReference(0)! as FileChooserParams;
+      expect(instance.isCaptureEnabled, false);
+      expect(instance.acceptTypes, const <String>['my', 'list']);
+      expect(instance.mode, FileChooserMode.openMultiple);
+      expect(instance.filenameHint, 'filenameHint');
     });
   });
 
@@ -1233,6 +1283,60 @@
 
       verify(mockApi.deny(instanceIdentifier));
     });
+  });
+
+  group('GeolocationPermissionsCallback', () {
+    tearDown(() {
+      TestGeolocationPermissionsCallbackHostApi.setup(null);
+    });
+
+    test('invoke', () async {
+      final MockTestGeolocationPermissionsCallbackHostApi mockApi =
+          MockTestGeolocationPermissionsCallbackHostApi();
+      TestGeolocationPermissionsCallbackHostApi.setup(mockApi);
+
+      final InstanceManager instanceManager = InstanceManager(
+        onWeakReferenceRemoved: (_) {},
+      );
+
+      final GeolocationPermissionsCallback instance =
+          GeolocationPermissionsCallback.detached(
+        instanceManager: instanceManager,
+      );
+      const int instanceIdentifier = 0;
+      instanceManager.addHostCreatedInstance(instance, instanceIdentifier);
+
+      const String origin = 'testString';
+      const bool allow = true;
+      const bool retain = true;
+
+      await instance.invoke(
+        origin,
+        allow,
+        retain,
+      );
+
+      verify(mockApi.invoke(instanceIdentifier, origin, allow, retain));
+    });
+
+    test('Geolocation FlutterAPI create', () {
+      final InstanceManager instanceManager = InstanceManager(
+        onWeakReferenceRemoved: (_) {},
+      );
+
+      final GeolocationPermissionsCallbackFlutterApiImpl api =
+          GeolocationPermissionsCallbackFlutterApiImpl(
+        instanceManager: instanceManager,
+      );
+
+      const int instanceIdentifier = 0;
+      api.create(instanceIdentifier);
+
+      expect(
+        instanceManager.getInstanceWithWeakReference(instanceIdentifier),
+        isA<GeolocationPermissionsCallback>(),
+      );
+    });
 
     test('FlutterAPI create', () {
       final InstanceManager instanceManager = InstanceManager(
diff --git a/packages/webview_flutter/webview_flutter_android/test/android_webview_test.mocks.dart b/packages/webview_flutter/webview_flutter_android/test/android_webview_test.mocks.dart
index 3b55d85..a7f825f 100644
--- a/packages/webview_flutter/webview_flutter_android/test/android_webview_test.mocks.dart
+++ b/packages/webview_flutter/webview_flutter_android/test/android_webview_test.mocks.dart
@@ -333,6 +333,36 @@
       );
 }
 
+/// A class which mocks [TestGeolocationPermissionsCallbackHostApi].
+///
+/// See the documentation for Mockito's code generation for more information.
+class MockTestGeolocationPermissionsCallbackHostApi extends _i1.Mock
+    implements _i6.TestGeolocationPermissionsCallbackHostApi {
+  MockTestGeolocationPermissionsCallbackHostApi() {
+    _i1.throwOnMissingStub(this);
+  }
+
+  @override
+  void invoke(
+    int? instanceId,
+    String? origin,
+    bool? allow,
+    bool? retain,
+  ) =>
+      super.noSuchMethod(
+        Invocation.method(
+          #invoke,
+          [
+            instanceId,
+            origin,
+            allow,
+            retain,
+          ],
+        ),
+        returnValueForMissingStub: null,
+      );
+}
+
 /// A class which mocks [TestInstanceManagerHostApi].
 ///
 /// See the documentation for Mockito's code generation for more information.
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 20b084e..98060e0 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
@@ -217,6 +217,7 @@
 
 class _TestWebViewHostApiCodec extends StandardMessageCodec {
   const _TestWebViewHostApiCodec();
+
   @override
   void writeValue(WriteBuffer buffer, Object? value) {
     if (value is WebViewPoint) {
@@ -1714,3 +1715,55 @@
     }
   }
 }
+
+/// Host API for `GeolocationPermissionsCallback`.
+///
+/// This class may handle instantiating and adding native object instances that
+/// are attached to a Dart instance or handle method calls on the associated
+/// native class or an instance of the class.
+///
+/// See https://developer.android.com/reference/android/webkit/GeolocationPermissions.Callback.
+abstract class TestGeolocationPermissionsCallbackHostApi {
+  static TestDefaultBinaryMessengerBinding? get _testBinaryMessengerBinding =>
+      TestDefaultBinaryMessengerBinding.instance;
+  static const MessageCodec<Object?> codec = StandardMessageCodec();
+
+  /// Handles Dart method `GeolocationPermissionsCallback.invoke`.
+  void invoke(int instanceId, String origin, bool allow, bool retain);
+
+  static void setup(TestGeolocationPermissionsCallbackHostApi? api,
+      {BinaryMessenger? binaryMessenger}) {
+    {
+      final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
+          'dev.flutter.pigeon.GeolocationPermissionsCallbackHostApi.invoke',
+          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.GeolocationPermissionsCallbackHostApi.invoke 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.GeolocationPermissionsCallbackHostApi.invoke was null, expected non-null int.');
+          final String? arg_origin = (args[1] as String?);
+          assert(arg_origin != null,
+              'Argument for dev.flutter.pigeon.GeolocationPermissionsCallbackHostApi.invoke was null, expected non-null String.');
+          final bool? arg_allow = (args[2] as bool?);
+          assert(arg_allow != null,
+              'Argument for dev.flutter.pigeon.GeolocationPermissionsCallbackHostApi.invoke was null, expected non-null bool.');
+          final bool? arg_retain = (args[3] as bool?);
+          assert(arg_retain != null,
+              'Argument for dev.flutter.pigeon.GeolocationPermissionsCallbackHostApi.invoke was null, expected non-null bool.');
+          api.invoke(arg_instanceId!, arg_origin!, arg_allow!, arg_retain!);
+          return <Object?>[];
+        });
+      }
+    }
+  }
+}