[webview_flutter_wkwebview] Add javascript panel interface for wkwebview (#5795)

* There are cases where Web calls System Popup with javascript on webview_flutter
* At this time, the message comes in the WKUIDelegate part in iOS.
   * https://developer.apple.com/documentation/webkit/wkuidelegate/1537406-webview
   * https://developer.apple.com/documentation/webkit/wkuidelegate/1536489-webview
* Related issue: https://github.com/flutter/flutter/issues/30358#issuecomment-1645347616
* Related Interface PR: https://github.com/flutter/packages/pull/5670
* The PR that contains all changes can be found at https://github.com/flutter/packages/pull/4704
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/CHANGELOG.md b/packages/webview_flutter/webview_flutter_wkwebview/CHANGELOG.md
index 5a97e3e..0d899a5 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/CHANGELOG.md
+++ b/packages/webview_flutter/webview_flutter_wkwebview/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 3.11.0
+
+* Adds support to show JavaScript dialog. See `PlatformWebViewController.setOnJavaScriptAlertDialog`, `PlatformWebViewController.setOnJavaScriptConfirmDialog` and `PlatformWebViewController.setOnJavaScriptTextInputDialog`.
+
 ## 3.10.3
 
 * Adds a check that throws an `ArgumentError` when `WebKitWebViewController.addJavaScriptChannel`
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 89ecad8..9d95849 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
@@ -1303,6 +1303,98 @@
     },
   );
 
+  testWidgets('can receive JavaScript alert dialogs',
+      (WidgetTester tester) async {
+    final PlatformWebViewController controller = PlatformWebViewController(
+      const PlatformWebViewControllerCreationParams(),
+    );
+
+    final Completer<String> alertMessage = Completer<String>();
+    unawaited(controller.setOnJavaScriptAlertDialog(
+      (JavaScriptAlertDialogRequest request) async {
+        alertMessage.complete(request.message);
+      },
+    ));
+
+    unawaited(controller.setJavaScriptMode(JavaScriptMode.unrestricted));
+    unawaited(
+      controller.loadRequest(LoadRequestParams(uri: Uri.parse(primaryUrl))),
+    );
+
+    await tester.pumpWidget(Builder(
+      builder: (BuildContext context) {
+        return PlatformWebViewWidget(
+          PlatformWebViewWidgetCreationParams(controller: controller),
+        ).build(context);
+      },
+    ));
+
+    await controller.runJavaScript('alert("alert message")');
+    await expectLater(alertMessage.future, completion('alert message'));
+  });
+
+  testWidgets('can receive JavaScript confirm dialogs',
+      (WidgetTester tester) async {
+    final PlatformWebViewController controller = PlatformWebViewController(
+      const PlatformWebViewControllerCreationParams(),
+    );
+
+    final Completer<String> confirmMessage = Completer<String>();
+    unawaited(controller.setOnJavaScriptConfirmDialog(
+      (JavaScriptConfirmDialogRequest request) async {
+        confirmMessage.complete(request.message);
+        return true;
+      },
+    ));
+
+    unawaited(controller.setJavaScriptMode(JavaScriptMode.unrestricted));
+    unawaited(
+      controller.loadRequest(LoadRequestParams(uri: Uri.parse(primaryUrl))),
+    );
+
+    await tester.pumpWidget(Builder(
+      builder: (BuildContext context) {
+        return PlatformWebViewWidget(
+          PlatformWebViewWidgetCreationParams(controller: controller),
+        ).build(context);
+      },
+    ));
+
+    await controller.runJavaScript('confirm("confirm message")');
+    await expectLater(confirmMessage.future, completion('confirm message'));
+  });
+
+  testWidgets('can receive JavaScript prompt dialogs',
+      (WidgetTester tester) async {
+    final PlatformWebViewController controller = PlatformWebViewController(
+      const PlatformWebViewControllerCreationParams(),
+    );
+
+    unawaited(controller.setOnJavaScriptTextInputDialog(
+      (JavaScriptTextInputDialogRequest request) async {
+        return 'return message';
+      },
+    ));
+
+    unawaited(controller.setJavaScriptMode(JavaScriptMode.unrestricted));
+    unawaited(
+      controller.loadRequest(LoadRequestParams(uri: Uri.parse(primaryUrl))),
+    );
+
+    await tester.pumpWidget(Builder(
+      builder: (BuildContext context) {
+        return PlatformWebViewWidget(
+          PlatformWebViewWidgetCreationParams(controller: controller),
+        ).build(context);
+      },
+    ));
+
+    final Object promptResponse = await controller.runJavaScriptReturningResult(
+      'prompt("input message", "default text")',
+    );
+    expect(promptResponse, 'return message');
+  });
+
   group('Logging', () {
     testWidgets('can receive console log messages',
         (WidgetTester tester) async {
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 cf80637..116f4bb 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/example/lib/main.dart
+++ b/packages/webview_flutter/webview_flutter_wkwebview/example/lib/main.dart
@@ -108,6 +108,38 @@
 </html>
 ''';
 
+const String kAlertTestPage = '''
+<!DOCTYPE html>
+<html>  
+   <head>     
+      <script type = "text/javascript">  
+            function showAlert(text) {	          
+	            alert(text);      
+            }  
+            
+            function showConfirm(text) {
+              var result = confirm(text);
+              alert(result);
+            }
+            
+            function showPrompt(text, defaultText) {
+              var inputString = prompt('Enter input', 'Default text');
+	            alert(inputString);            
+            }            
+      </script>       
+   </head>  
+     
+   <body>  
+      <p> Click the following button to see the effect </p>        
+      <form>  
+        <input type = "button" value = "Alert" onclick = "showAlert('Test Alert');" />
+        <input type = "button" value = "Confirm" onclick = "showConfirm('Test Confirm');" />  
+        <input type = "button" value = "Prompt" onclick = "showPrompt('Test Prompt', 'Default Value');" />    
+      </form>       
+   </body>  
+</html>  
+''';
+
 class WebViewExample extends StatefulWidget {
   const WebViewExample({super.key, this.cookieManager});
 
@@ -297,6 +329,7 @@
   setCookie,
   logExample,
   basicAuthentication,
+  javaScriptAlert,
 }
 
 class SampleMenu extends StatelessWidget {
@@ -348,6 +381,8 @@
             _onLogExample();
           case MenuOptions.basicAuthentication:
             _promptForUrl(context);
+          case MenuOptions.javaScriptAlert:
+            _onJavaScriptAlertExample(context);
         }
       },
       itemBuilder: (BuildContext context) => <PopupMenuItem<MenuOptions>>[
@@ -412,6 +447,10 @@
           value: MenuOptions.basicAuthentication,
           child: Text('Basic Authentication Example'),
         ),
+        const PopupMenuItem<MenuOptions>(
+          value: MenuOptions.javaScriptAlert,
+          child: Text('JavaScript Alert Example'),
+        ),
       ],
     );
   }
@@ -536,6 +575,28 @@
     return webViewController.loadHtmlString(kTransparentBackgroundPage);
   }
 
+  Future<void> _onJavaScriptAlertExample(BuildContext context) {
+    webViewController.setOnJavaScriptAlertDialog(
+        (JavaScriptAlertDialogRequest request) async {
+      await _showAlert(context, request.message);
+    });
+
+    webViewController.setOnJavaScriptConfirmDialog(
+        (JavaScriptConfirmDialogRequest request) async {
+      final bool result = await _showConfirm(context, request.message);
+      return result;
+    });
+
+    webViewController.setOnJavaScriptTextInputDialog(
+        (JavaScriptTextInputDialogRequest request) async {
+      final String result =
+          await _showTextInput(context, request.message, request.defaultText);
+      return result;
+    });
+
+    return webViewController.loadHtmlString(kAlertTestPage);
+  }
+
   Widget _getCookieList(String cookies) {
     if (cookies == '""') {
       return Container();
@@ -605,6 +666,65 @@
       },
     );
   }
+
+  Future<void> _showAlert(BuildContext context, String message) async {
+    return showDialog<void>(
+        context: context,
+        builder: (BuildContext ctx) {
+          return AlertDialog(
+            content: Text(message),
+            actions: <Widget>[
+              TextButton(
+                  onPressed: () {
+                    Navigator.of(ctx).pop();
+                  },
+                  child: const Text('OK'))
+            ],
+          );
+        });
+  }
+
+  Future<bool> _showConfirm(BuildContext context, String message) async {
+    return await showDialog<bool>(
+            context: context,
+            builder: (BuildContext ctx) {
+              return AlertDialog(
+                content: Text(message),
+                actions: <Widget>[
+                  TextButton(
+                      onPressed: () {
+                        Navigator.of(ctx).pop(false);
+                      },
+                      child: const Text('Cancel')),
+                  TextButton(
+                      onPressed: () {
+                        Navigator.of(ctx).pop(true);
+                      },
+                      child: const Text('OK')),
+                ],
+              );
+            }) ??
+        false;
+  }
+
+  Future<String> _showTextInput(
+      BuildContext context, String message, String? defaultText) async {
+    return await showDialog<String>(
+            context: context,
+            builder: (BuildContext ctx) {
+              return AlertDialog(
+                content: Text(message),
+                actions: <Widget>[
+                  TextButton(
+                      onPressed: () {
+                        Navigator.of(ctx).pop('Text test');
+                      },
+                      child: const Text('Enter')),
+                ],
+              );
+            }) ??
+        '';
+  }
 }
 
 class NavigationControls extends StatelessWidget {
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/example/pubspec.yaml b/packages/webview_flutter/webview_flutter_wkwebview/example/pubspec.yaml
index 900520f..5d323b7 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.7.0
+  webview_flutter_platform_interface: ^2.9.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/FWFDataConverters.m b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFDataConverters.m
index a4dda8b..9a5cc86 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFDataConverters.m
+++ b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFDataConverters.m
@@ -167,7 +167,7 @@
 
 FWFNSUrlRequestData *FWFNSUrlRequestDataFromNativeNSURLRequest(NSURLRequest *request) {
   return [FWFNSUrlRequestData
-              makeWithUrl:request.URL.absoluteString
+              makeWithUrl:request.URL.absoluteString == nil ? @"" : request.URL.absoluteString
                httpMethod:request.HTTPMethod
                  httpBody:request.HTTPBody
                               ? [FlutterStandardTypedData typedDataWithBytes:request.HTTPBody]
@@ -176,7 +176,9 @@
 }
 
 FWFWKFrameInfoData *FWFWKFrameInfoDataFromNativeWKFrameInfo(WKFrameInfo *info) {
-  return [FWFWKFrameInfoData makeWithIsMainFrame:info.isMainFrame];
+  return [FWFWKFrameInfoData
+      makeWithIsMainFrame:info.isMainFrame
+                  request:FWFNSUrlRequestDataFromNativeNSURLRequest(info.request)];
 }
 
 WKNavigationActionPolicy FWFNativeWKNavigationActionPolicyFromEnumData(
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 1e312a2..a0524d0 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFGeneratedWebKitApis.h
+++ b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFGeneratedWebKitApis.h
@@ -464,8 +464,9 @@
 @interface FWFWKFrameInfoData : NSObject
 /// `init` unavailable to enforce nonnull fields, see the `make` class method.
 - (instancetype)init NS_UNAVAILABLE;
-+ (instancetype)makeWithIsMainFrame:(BOOL)isMainFrame;
++ (instancetype)makeWithIsMainFrame:(BOOL)isMainFrame request:(FWFNSUrlRequestData *)request;
 @property(nonatomic, assign) BOOL isMainFrame;
+@property(nonatomic, strong) FWFNSUrlRequestData *request;
 @end
 
 /// Mirror of NSError.
@@ -949,6 +950,27 @@
                                                         (void (^)(
                                                             FWFWKPermissionDecisionData *_Nullable,
                                                             FlutterError *_Nullable))completion;
+/// Callback to Dart function `WKUIDelegate.runJavaScriptAlertPanel`.
+- (void)runJavaScriptAlertPanelForDelegateWithIdentifier:(NSInteger)identifier
+                                                 message:(NSString *)message
+                                                   frame:(FWFWKFrameInfoData *)frame
+                                              completion:
+                                                  (void (^)(FlutterError *_Nullable))completion;
+/// Callback to Dart function `WKUIDelegate.runJavaScriptConfirmPanel`.
+- (void)runJavaScriptConfirmPanelForDelegateWithIdentifier:(NSInteger)identifier
+                                                   message:(NSString *)message
+                                                     frame:(FWFWKFrameInfoData *)frame
+                                                completion:
+                                                    (void (^)(NSNumber *_Nullable,
+                                                              FlutterError *_Nullable))completion;
+/// Callback to Dart function `WKUIDelegate.runJavaScriptTextInputPanel`.
+- (void)runJavaScriptTextInputPanelForDelegateWithIdentifier:(NSInteger)identifier
+                                                      prompt:(NSString *)prompt
+                                                 defaultText:(NSString *)defaultText
+                                                       frame:(FWFWKFrameInfoData *)frame
+                                                  completion:
+                                                      (void (^)(NSString *_Nullable,
+                                                                FlutterError *_Nullable))completion;
 @end
 
 /// The codec used by FWFWKHttpCookieStoreHostApi.
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 5d80178..c9cd996 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFGeneratedWebKitApis.m
+++ b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFGeneratedWebKitApis.m
@@ -609,14 +609,16 @@
 @end
 
 @implementation FWFWKFrameInfoData
-+ (instancetype)makeWithIsMainFrame:(BOOL)isMainFrame {
++ (instancetype)makeWithIsMainFrame:(BOOL)isMainFrame request:(FWFNSUrlRequestData *)request {
   FWFWKFrameInfoData *pigeonResult = [[FWFWKFrameInfoData alloc] init];
   pigeonResult.isMainFrame = isMainFrame;
+  pigeonResult.request = request;
   return pigeonResult;
 }
 + (FWFWKFrameInfoData *)fromList:(NSArray *)list {
   FWFWKFrameInfoData *pigeonResult = [[FWFWKFrameInfoData alloc] init];
   pigeonResult.isMainFrame = [GetNullableObjectAtIndex(list, 0) boolValue];
+  pigeonResult.request = [FWFNSUrlRequestData nullableFromList:(GetNullableObjectAtIndex(list, 1))];
   return pigeonResult;
 }
 + (nullable FWFWKFrameInfoData *)nullableFromList:(NSArray *)list {
@@ -625,6 +627,7 @@
 - (NSArray *)toList {
   return @[
     @(self.isMainFrame),
+    (self.request ? [self.request toList] : [NSNull null]),
   ];
 }
 @end
@@ -3098,6 +3101,99 @@
               }
             }];
 }
+- (void)runJavaScriptAlertPanelForDelegateWithIdentifier:(NSInteger)arg_identifier
+                                                 message:(NSString *)arg_message
+                                                   frame:(FWFWKFrameInfoData *)arg_frame
+                                              completion:
+                                                  (void (^)(FlutterError *_Nullable))completion {
+  FlutterBasicMessageChannel *channel = [FlutterBasicMessageChannel
+      messageChannelWithName:@"dev.flutter.pigeon.webview_flutter_wkwebview.WKUIDelegateFlutterApi."
+                             @"runJavaScriptAlertPanel"
+             binaryMessenger:self.binaryMessenger
+                       codec:FWFWKUIDelegateFlutterApiGetCodec()];
+  [channel
+      sendMessage:@[ @(arg_identifier), arg_message ?: [NSNull null], arg_frame ?: [NSNull null] ]
+            reply:^(NSArray<id> *reply) {
+              if (reply != nil) {
+                if (reply.count > 1) {
+                  completion([FlutterError errorWithCode:reply[0]
+                                                 message:reply[1]
+                                                 details:reply[2]]);
+                } else {
+                  completion(nil);
+                }
+              } else {
+                completion([FlutterError errorWithCode:@"channel-error"
+                                               message:@"Unable to establish connection on channel."
+                                               details:@""]);
+              }
+            }];
+}
+- (void)runJavaScriptConfirmPanelForDelegateWithIdentifier:(NSInteger)arg_identifier
+                                                   message:(NSString *)arg_message
+                                                     frame:(FWFWKFrameInfoData *)arg_frame
+                                                completion:
+                                                    (void (^)(NSNumber *_Nullable,
+                                                              FlutterError *_Nullable))completion {
+  FlutterBasicMessageChannel *channel = [FlutterBasicMessageChannel
+      messageChannelWithName:@"dev.flutter.pigeon.webview_flutter_wkwebview.WKUIDelegateFlutterApi."
+                             @"runJavaScriptConfirmPanel"
+             binaryMessenger:self.binaryMessenger
+                       codec:FWFWKUIDelegateFlutterApiGetCodec()];
+  [channel
+      sendMessage:@[ @(arg_identifier), arg_message ?: [NSNull null], arg_frame ?: [NSNull null] ]
+            reply:^(NSArray<id> *reply) {
+              if (reply != nil) {
+                if (reply.count > 1) {
+                  completion(nil, [FlutterError errorWithCode:reply[0]
+                                                      message:reply[1]
+                                                      details:reply[2]]);
+                } else {
+                  NSNumber *output = reply[0] == [NSNull null] ? nil : reply[0];
+                  completion(output, nil);
+                }
+              } else {
+                completion(nil,
+                           [FlutterError errorWithCode:@"channel-error"
+                                               message:@"Unable to establish connection on channel."
+                                               details:@""]);
+              }
+            }];
+}
+- (void)runJavaScriptTextInputPanelForDelegateWithIdentifier:(NSInteger)arg_identifier
+                                                      prompt:(NSString *)arg_prompt
+                                                 defaultText:(NSString *)arg_defaultText
+                                                       frame:(FWFWKFrameInfoData *)arg_frame
+                                                  completion:(void (^)(NSString *_Nullable,
+                                                                       FlutterError *_Nullable))
+                                                                 completion {
+  FlutterBasicMessageChannel *channel = [FlutterBasicMessageChannel
+      messageChannelWithName:@"dev.flutter.pigeon.webview_flutter_wkwebview.WKUIDelegateFlutterApi."
+                             @"runJavaScriptTextInputPanel"
+             binaryMessenger:self.binaryMessenger
+                       codec:FWFWKUIDelegateFlutterApiGetCodec()];
+  [channel sendMessage:@[
+    @(arg_identifier), arg_prompt ?: [NSNull null], arg_defaultText ?: [NSNull null],
+    arg_frame ?: [NSNull null]
+  ]
+                 reply:^(NSArray<id> *reply) {
+                   if (reply != nil) {
+                     if (reply.count > 1) {
+                       completion(nil, [FlutterError errorWithCode:reply[0]
+                                                           message:reply[1]
+                                                           details:reply[2]]);
+                     } else {
+                       NSString *output = reply[0] == [NSNull null] ? nil : reply[0];
+                       completion(output, nil);
+                     }
+                   } else {
+                     completion(nil, [FlutterError
+                                         errorWithCode:@"channel-error"
+                                               message:@"Unable to establish connection on channel."
+                                               details:@""]);
+                   }
+                 }];
+}
 @end
 
 @interface FWFWKHttpCookieStoreHostApiCodecReader : FlutterStandardReader
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFUIDelegateHostApi.m b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFUIDelegateHostApi.m
index 879d85d..f9d78ea 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFUIDelegateHostApi.m
+++ b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFUIDelegateHostApi.m
@@ -88,6 +88,63 @@
                                                             decision));
                                                   }];
 }
+
+- (void)runJavaScriptAlertPanelForDelegateWithIdentifier:(FWFUIDelegate *)instance
+                                                 message:(NSString *)message
+                                                   frame:(WKFrameInfo *)frame
+                                       completionHandler:(void (^)(void))completionHandler {
+  [self runJavaScriptAlertPanelForDelegateWithIdentifier:[self identifierForDelegate:instance]
+                                                 message:message
+                                                   frame:FWFWKFrameInfoDataFromNativeWKFrameInfo(
+                                                             frame)
+                                              completion:^(FlutterError *error) {
+                                                NSAssert(!error, @"%@", error);
+                                                completionHandler();
+                                              }];
+}
+
+- (void)runJavaScriptConfirmPanelForDelegateWithIdentifier:(FWFUIDelegate *)instance
+                                                   message:(NSString *)message
+                                                     frame:(WKFrameInfo *)frame
+                                         completionHandler:(void (^)(BOOL))completionHandler {
+  [self runJavaScriptConfirmPanelForDelegateWithIdentifier:[self identifierForDelegate:instance]
+                                                   message:message
+                                                     frame:FWFWKFrameInfoDataFromNativeWKFrameInfo(
+                                                               frame)
+                                                completion:^(NSNumber *isConfirmed,
+                                                             FlutterError *error) {
+                                                  NSAssert(!error, @"%@", error);
+                                                  if (error) {
+                                                    completionHandler(NO);
+                                                  } else {
+                                                    completionHandler(isConfirmed.boolValue);
+                                                  }
+                                                }];
+}
+
+- (void)runJavaScriptTextInputPanelForDelegateWithIdentifier:(FWFUIDelegate *)instance
+                                                      prompt:(NSString *)prompt
+                                                 defaultText:(NSString *)defaultText
+                                                       frame:(WKFrameInfo *)frame
+                                           completionHandler:
+                                               (void (^)(NSString *_Nullable))completionHandler {
+  [self
+      runJavaScriptTextInputPanelForDelegateWithIdentifier:[self identifierForDelegate:instance]
+                                                    prompt:prompt
+                                               defaultText:defaultText
+                                                     frame:FWFWKFrameInfoDataFromNativeWKFrameInfo(
+                                                               frame)
+                                                completion:^(NSString *inputText,
+                                                             FlutterError *error) {
+                                                  NSAssert(!error, @"%@", error);
+                                                  if (error) {
+                                                    completionHandler(nil);
+                                                  } else {
+                                                    completionHandler(inputText);
+                                                  }
+                                                }];
+}
+
 @end
 
 @implementation FWFUIDelegate
@@ -131,6 +188,39 @@
                                                     decisionHandler(decision);
                                                   }];
 }
+
+- (void)webView:(WKWebView *)webView
+    runJavaScriptAlertPanelWithMessage:(NSString *)message
+                      initiatedByFrame:(WKFrameInfo *)frame
+                     completionHandler:(void (^)(void))completionHandler {
+  [self.UIDelegateAPI runJavaScriptAlertPanelForDelegateWithIdentifier:self
+                                                               message:message
+                                                                 frame:frame
+                                                     completionHandler:completionHandler];
+}
+
+- (void)webView:(WKWebView *)webView
+    runJavaScriptConfirmPanelWithMessage:(NSString *)message
+                        initiatedByFrame:(WKFrameInfo *)frame
+                       completionHandler:(void (^)(BOOL))completionHandler {
+  [self.UIDelegateAPI runJavaScriptConfirmPanelForDelegateWithIdentifier:self
+                                                                 message:message
+                                                                   frame:frame
+                                                       completionHandler:completionHandler];
+}
+
+- (void)webView:(WKWebView *)webView
+    runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt
+                              defaultText:(NSString *)defaultText
+                         initiatedByFrame:(WKFrameInfo *)frame
+                        completionHandler:(void (^)(NSString *_Nullable))completionHandler {
+  [self.UIDelegateAPI runJavaScriptTextInputPanelForDelegateWithIdentifier:self
+                                                                    prompt:prompt
+                                                               defaultText:defaultText
+                                                                     frame:frame
+                                                         completionHandler:completionHandler];
+}
+
 @end
 
 @interface FWFUIDelegateHostApiImpl ()
@@ -161,4 +251,5 @@
                                                              instanceManager:self.instanceManager];
   [self.instanceManager addDartCreatedInstance:uIDelegate withIdentifier:identifier];
 }
+
 @end
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 1c63220..f814bd0 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
@@ -560,13 +560,17 @@
 class WKFrameInfoData {
   WKFrameInfoData({
     required this.isMainFrame,
+    required this.request,
   });
 
   bool isMainFrame;
 
+  NSUrlRequestData request;
+
   Object encode() {
     return <Object?>[
       isMainFrame,
+      request.encode(),
     ];
   }
 
@@ -574,6 +578,7 @@
     result as List<Object?>;
     return WKFrameInfoData(
       isMainFrame: result[0]! as bool,
+      request: NSUrlRequestData.decode(result[1]! as List<Object?>),
     );
   }
 }
@@ -2919,6 +2924,18 @@
       WKFrameInfoData frame,
       WKMediaCaptureTypeData type);
 
+  /// Callback to Dart function `WKUIDelegate.runJavaScriptAlertPanel`.
+  Future<void> runJavaScriptAlertPanel(
+      int identifier, String message, WKFrameInfoData frame);
+
+  /// Callback to Dart function `WKUIDelegate.runJavaScriptConfirmPanel`.
+  Future<bool> runJavaScriptConfirmPanel(
+      int identifier, String message, WKFrameInfoData frame);
+
+  /// Callback to Dart function `WKUIDelegate.runJavaScriptTextInputPanel`.
+  Future<String> runJavaScriptTextInputPanel(
+      int identifier, String prompt, String defaultText, WKFrameInfoData frame);
+
   static void setup(WKUIDelegateFlutterApi? api,
       {BinaryMessenger? binaryMessenger}) {
     {
@@ -3002,6 +3019,111 @@
         });
       }
     }
+    {
+      final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
+          'dev.flutter.pigeon.webview_flutter_wkwebview.WKUIDelegateFlutterApi.runJavaScriptAlertPanel',
+          codec,
+          binaryMessenger: binaryMessenger);
+      if (api == null) {
+        channel.setMessageHandler(null);
+      } else {
+        channel.setMessageHandler((Object? message) async {
+          assert(message != null,
+              'Argument for dev.flutter.pigeon.webview_flutter_wkwebview.WKUIDelegateFlutterApi.runJavaScriptAlertPanel 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.webview_flutter_wkwebview.WKUIDelegateFlutterApi.runJavaScriptAlertPanel was null, expected non-null int.');
+          final String? arg_message = (args[1] as String?);
+          assert(arg_message != null,
+              'Argument for dev.flutter.pigeon.webview_flutter_wkwebview.WKUIDelegateFlutterApi.runJavaScriptAlertPanel was null, expected non-null String.');
+          final WKFrameInfoData? arg_frame = (args[2] as WKFrameInfoData?);
+          assert(arg_frame != null,
+              'Argument for dev.flutter.pigeon.webview_flutter_wkwebview.WKUIDelegateFlutterApi.runJavaScriptAlertPanel was null, expected non-null WKFrameInfoData.');
+          try {
+            await api.runJavaScriptAlertPanel(
+                arg_identifier!, arg_message!, arg_frame!);
+            return wrapResponse(empty: true);
+          } on PlatformException catch (e) {
+            return wrapResponse(error: e);
+          } catch (e) {
+            return wrapResponse(
+                error: PlatformException(code: 'error', message: e.toString()));
+          }
+        });
+      }
+    }
+    {
+      final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
+          'dev.flutter.pigeon.webview_flutter_wkwebview.WKUIDelegateFlutterApi.runJavaScriptConfirmPanel',
+          codec,
+          binaryMessenger: binaryMessenger);
+      if (api == null) {
+        channel.setMessageHandler(null);
+      } else {
+        channel.setMessageHandler((Object? message) async {
+          assert(message != null,
+              'Argument for dev.flutter.pigeon.webview_flutter_wkwebview.WKUIDelegateFlutterApi.runJavaScriptConfirmPanel 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.webview_flutter_wkwebview.WKUIDelegateFlutterApi.runJavaScriptConfirmPanel was null, expected non-null int.');
+          final String? arg_message = (args[1] as String?);
+          assert(arg_message != null,
+              'Argument for dev.flutter.pigeon.webview_flutter_wkwebview.WKUIDelegateFlutterApi.runJavaScriptConfirmPanel was null, expected non-null String.');
+          final WKFrameInfoData? arg_frame = (args[2] as WKFrameInfoData?);
+          assert(arg_frame != null,
+              'Argument for dev.flutter.pigeon.webview_flutter_wkwebview.WKUIDelegateFlutterApi.runJavaScriptConfirmPanel was null, expected non-null WKFrameInfoData.');
+          try {
+            final bool output = await api.runJavaScriptConfirmPanel(
+                arg_identifier!, arg_message!, arg_frame!);
+            return wrapResponse(result: output);
+          } on PlatformException catch (e) {
+            return wrapResponse(error: e);
+          } catch (e) {
+            return wrapResponse(
+                error: PlatformException(code: 'error', message: e.toString()));
+          }
+        });
+      }
+    }
+    {
+      final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
+          'dev.flutter.pigeon.webview_flutter_wkwebview.WKUIDelegateFlutterApi.runJavaScriptTextInputPanel',
+          codec,
+          binaryMessenger: binaryMessenger);
+      if (api == null) {
+        channel.setMessageHandler(null);
+      } else {
+        channel.setMessageHandler((Object? message) async {
+          assert(message != null,
+              'Argument for dev.flutter.pigeon.webview_flutter_wkwebview.WKUIDelegateFlutterApi.runJavaScriptTextInputPanel 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.webview_flutter_wkwebview.WKUIDelegateFlutterApi.runJavaScriptTextInputPanel was null, expected non-null int.');
+          final String? arg_prompt = (args[1] as String?);
+          assert(arg_prompt != null,
+              'Argument for dev.flutter.pigeon.webview_flutter_wkwebview.WKUIDelegateFlutterApi.runJavaScriptTextInputPanel was null, expected non-null String.');
+          final String? arg_defaultText = (args[2] as String?);
+          assert(arg_defaultText != null,
+              'Argument for dev.flutter.pigeon.webview_flutter_wkwebview.WKUIDelegateFlutterApi.runJavaScriptTextInputPanel was null, expected non-null String.');
+          final WKFrameInfoData? arg_frame = (args[3] as WKFrameInfoData?);
+          assert(arg_frame != null,
+              'Argument for dev.flutter.pigeon.webview_flutter_wkwebview.WKUIDelegateFlutterApi.runJavaScriptTextInputPanel was null, expected non-null WKFrameInfoData.');
+          try {
+            final String output = await api.runJavaScriptTextInputPanel(
+                arg_identifier!, arg_prompt!, arg_defaultText!, arg_frame!);
+            return wrapResponse(result: output);
+          } on PlatformException catch (e) {
+            return wrapResponse(error: e);
+          } catch (e) {
+            return wrapResponse(
+                error: PlatformException(code: 'error', message: e.toString()));
+          }
+        });
+      }
+    }
   }
 }
 
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/lib/src/web_kit/web_kit.dart b/packages/webview_flutter/webview_flutter_wkwebview/lib/src/web_kit/web_kit.dart
index d157b3c..fb99be0 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/lib/src/web_kit/web_kit.dart
+++ b/packages/webview_flutter/webview_flutter_wkwebview/lib/src/web_kit/web_kit.dart
@@ -172,10 +172,16 @@
 @immutable
 class WKFrameInfo {
   /// Construct a [WKFrameInfo].
-  const WKFrameInfo({required this.isMainFrame});
+  const WKFrameInfo({
+    required this.isMainFrame,
+    required this.request,
+  });
 
   /// Indicates whether the frame is the web site's main frame or a subframe.
   final bool isMainFrame;
+
+  /// The URL request object associated with the navigation action.
+  final NSUrlRequest request;
 }
 
 /// A script that the web view injects into a webpage.
@@ -728,6 +734,9 @@
   WKUIDelegate({
     this.onCreateWebView,
     this.requestMediaCapturePermission,
+    this.runJavaScriptAlertDialog,
+    this.runJavaScriptConfirmDialog,
+    this.runJavaScriptTextInputDialog,
     super.observeValue,
     super.binaryMessenger,
     super.instanceManager,
@@ -749,6 +758,9 @@
   WKUIDelegate.detached({
     this.onCreateWebView,
     this.requestMediaCapturePermission,
+    this.runJavaScriptAlertDialog,
+    this.runJavaScriptConfirmDialog,
+    this.runJavaScriptTextInputDialog,
     super.observeValue,
     super.binaryMessenger,
     super.instanceManager,
@@ -780,11 +792,30 @@
     WKMediaCaptureType type,
   )? requestMediaCapturePermission;
 
+  /// Notifies the host application that the web page
+  /// wants to display a JavaScript alert() dialog.
+  final Future<void> Function(String message, WKFrameInfo frame)?
+      runJavaScriptAlertDialog;
+
+  /// Notifies the host application that the web page
+  /// wants to display a JavaScript confirm() dialog.
+  final Future<bool> Function(String message, WKFrameInfo frame)?
+      runJavaScriptConfirmDialog;
+
+  /// Notifies the host application that the web page
+  /// wants to display a JavaScript prompt() dialog.
+  final Future<String> Function(
+          String prompt, String defaultText, WKFrameInfo frame)?
+      runJavaScriptTextInputDialog;
+
   @override
   WKUIDelegate copy() {
     return WKUIDelegate.detached(
       onCreateWebView: onCreateWebView,
       requestMediaCapturePermission: requestMediaCapturePermission,
+      runJavaScriptAlertDialog: runJavaScriptAlertDialog,
+      runJavaScriptConfirmDialog: runJavaScriptConfirmDialog,
+      runJavaScriptTextInputDialog: runJavaScriptTextInputDialog,
       observeValue: observeValue,
       binaryMessenger: _uiDelegateApi.binaryMessenger,
       instanceManager: _uiDelegateApi.instanceManager,
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/lib/src/web_kit/web_kit_api_impls.dart b/packages/webview_flutter/webview_flutter_wkwebview/lib/src/web_kit/web_kit_api_impls.dart
index de28939..9c94bcb 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/lib/src/web_kit/web_kit_api_impls.dart
+++ b/packages/webview_flutter/webview_flutter_wkwebview/lib/src/web_kit/web_kit_api_impls.dart
@@ -153,7 +153,10 @@
 
 extension _WKFrameInfoDataConverter on WKFrameInfoData {
   WKFrameInfo toWKFrameInfo() {
-    return WKFrameInfo(isMainFrame: isMainFrame);
+    return WKFrameInfo(
+      isMainFrame: isMainFrame,
+      request: request.toNSUrlRequest(),
+    );
   }
 }
 
@@ -741,6 +744,33 @@
 
     return WKPermissionDecisionData(value: decision);
   }
+
+  @override
+  Future<void> runJavaScriptAlertPanel(
+      int identifier, String message, WKFrameInfoData frame) {
+    final WKUIDelegate instance =
+        instanceManager.getInstanceWithWeakReference(identifier)!;
+    return instance.runJavaScriptAlertDialog!
+        .call(message, frame.toWKFrameInfo());
+  }
+
+  @override
+  Future<bool> runJavaScriptConfirmPanel(
+      int identifier, String message, WKFrameInfoData frame) {
+    final WKUIDelegate instance =
+        instanceManager.getInstanceWithWeakReference(identifier)!;
+    return instance.runJavaScriptConfirmDialog!
+        .call(message, frame.toWKFrameInfo());
+  }
+
+  @override
+  Future<String> runJavaScriptTextInputPanel(int identifier, String prompt,
+      String defaultText, WKFrameInfoData frame) {
+    final WKUIDelegate instance =
+        instanceManager.getInstanceWithWeakReference(identifier)!;
+    return instance.runJavaScriptTextInputDialog!
+        .call(prompt, defaultText, frame.toWKFrameInfo());
+  }
 }
 
 /// Host api implementation for [WKNavigationDelegate].
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/lib/src/webkit_proxy.dart b/packages/webview_flutter/webview_flutter_wkwebview/lib/src/webkit_proxy.dart
index 4b0c4cc..3a21bc9 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/lib/src/webkit_proxy.dart
+++ b/packages/webview_flutter/webview_flutter_wkwebview/lib/src/webkit_proxy.dart
@@ -95,6 +95,19 @@
       WKFrameInfo frame,
       WKMediaCaptureType type,
     )? requestMediaCapturePermission,
+    Future<void> Function(
+      String message,
+      WKFrameInfo frame,
+    )? runJavaScriptAlertDialog,
+    Future<bool> Function(
+      String message,
+      WKFrameInfo frame,
+    )? runJavaScriptConfirmDialog,
+    Future<String> Function(
+      String prompt,
+      String defaultText,
+      WKFrameInfo frame,
+    )? runJavaScriptTextInputDialog,
     InstanceManager? instanceManager,
   }) createUIDelegate;
 }
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 357ab94..66b04c5 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
@@ -220,6 +220,46 @@
           return decisionCompleter.future;
         }
       },
+      runJavaScriptAlertDialog: (String message, WKFrameInfo frame) async {
+        final Future<void> Function(JavaScriptAlertDialogRequest request)?
+            callback = weakThis.target?._onJavaScriptAlertDialog;
+        if (callback != null) {
+          final JavaScriptAlertDialogRequest request =
+              JavaScriptAlertDialogRequest(
+                  message: message, url: frame.request.url);
+          await callback.call(request);
+          return;
+        }
+      },
+      runJavaScriptConfirmDialog: (String message, WKFrameInfo frame) async {
+        final Future<bool> Function(JavaScriptConfirmDialogRequest request)?
+            callback = weakThis.target?._onJavaScriptConfirmDialog;
+        if (callback != null) {
+          final JavaScriptConfirmDialogRequest request =
+              JavaScriptConfirmDialogRequest(
+                  message: message, url: frame.request.url);
+          final bool result = await callback.call(request);
+          return result;
+        }
+
+        return false;
+      },
+      runJavaScriptTextInputDialog:
+          (String prompt, String defaultText, WKFrameInfo frame) async {
+        final Future<String> Function(JavaScriptTextInputDialogRequest request)?
+            callback = weakThis.target?._onJavaScriptTextInputDialog;
+        if (callback != null) {
+          final JavaScriptTextInputDialogRequest request =
+              JavaScriptTextInputDialogRequest(
+                  message: prompt,
+                  url: frame.request.url,
+                  defaultText: defaultText);
+          final String result = await callback.call(request);
+          return result;
+        }
+
+        return '';
+      },
     );
 
     _webView.setUIDelegate(_uiDelegate);
@@ -274,6 +314,13 @@
   void Function(JavaScriptConsoleMessage)? _onConsoleMessageCallback;
   void Function(PlatformWebViewPermissionRequest)? _onPermissionRequestCallback;
 
+  Future<void> Function(JavaScriptAlertDialogRequest request)?
+      _onJavaScriptAlertDialog;
+  Future<bool> Function(JavaScriptConfirmDialogRequest request)?
+      _onJavaScriptConfirmDialog;
+  Future<String> Function(JavaScriptTextInputDialogRequest request)?
+      _onJavaScriptTextInputDialog;
+
   WebKitWebViewControllerCreationParams get _webKitParams =>
       params as WebKitWebViewControllerCreationParams;
 
@@ -680,6 +727,27 @@
     return (await _webView.evaluateJavaScript('navigator.userAgent;')
         as String?)!;
   }
+
+  @override
+  Future<void> setOnJavaScriptAlertDialog(
+      Future<void> Function(JavaScriptAlertDialogRequest request)
+          onJavaScriptAlertDialog) async {
+    _onJavaScriptAlertDialog = onJavaScriptAlertDialog;
+  }
+
+  @override
+  Future<void> setOnJavaScriptConfirmDialog(
+      Future<bool> Function(JavaScriptConfirmDialogRequest request)
+          onJavaScriptConfirmDialog) async {
+    _onJavaScriptConfirmDialog = onJavaScriptConfirmDialog;
+  }
+
+  @override
+  Future<void> setOnJavaScriptTextInputDialog(
+      Future<String> Function(JavaScriptTextInputDialogRequest request)
+          onJavaScriptTextInputDialog) async {
+    _onJavaScriptTextInputDialog = onJavaScriptTextInputDialog;
+  }
 }
 
 /// An implementation of [JavaScriptChannelParams] with the WebKit api.
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 c489469..d5fe530 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/pigeons/web_kit.dart
+++ b/packages/webview_flutter/webview_flutter_wkwebview/pigeons/web_kit.dart
@@ -343,6 +343,7 @@
 /// See https://developer.apple.com/documentation/webkit/wkframeinfo?language=objc.
 class WKFrameInfoData {
   late bool isMainFrame;
+  late NSUrlRequestData request;
 }
 
 /// Mirror of NSError.
@@ -805,6 +806,40 @@
     WKFrameInfoData frame,
     WKMediaCaptureTypeData type,
   );
+
+  /// Callback to Dart function `WKUIDelegate.runJavaScriptAlertPanel`.
+  @ObjCSelector(
+    'runJavaScriptAlertPanelForDelegateWithIdentifier:message:frame:',
+  )
+  @async
+  void runJavaScriptAlertPanel(
+    int identifier,
+    String message,
+    WKFrameInfoData frame,
+  );
+
+  /// Callback to Dart function `WKUIDelegate.runJavaScriptConfirmPanel`.
+  @ObjCSelector(
+    'runJavaScriptConfirmPanelForDelegateWithIdentifier:message:frame:',
+  )
+  @async
+  bool runJavaScriptConfirmPanel(
+    int identifier,
+    String message,
+    WKFrameInfoData frame,
+  );
+
+  /// Callback to Dart function `WKUIDelegate.runJavaScriptTextInputPanel`.
+  @ObjCSelector(
+    'runJavaScriptTextInputPanelForDelegateWithIdentifier:prompt:defaultText:frame:',
+  )
+  @async
+  String runJavaScriptTextInputPanel(
+    int identifier,
+    String prompt,
+    String defaultText,
+    WKFrameInfoData frame,
+  );
 }
 
 /// Mirror of WKHttpCookieStore.
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/pubspec.yaml b/packages/webview_flutter/webview_flutter_wkwebview/pubspec.yaml
index 572f1d8..2f14ca1 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.10.3
+version: 3.11.0
 
 environment:
   sdk: ^3.2.3
@@ -20,7 +20,7 @@
   flutter:
     sdk: flutter
   path: ^1.8.0
-  webview_flutter_platform_interface: ^2.7.0
+  webview_flutter_platform_interface: ^2.9.0
 
 dev_dependencies:
   build_runner: ^2.1.5
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/test/legacy/web_kit_webview_widget_test.dart b/packages/webview_flutter/webview_flutter_wkwebview/test/legacy/web_kit_webview_widget_test.dart
index ebeb3d9..8c42119 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/test/legacy/web_kit_webview_widget_test.dart
+++ b/packages/webview_flutter/webview_flutter_wkwebview/test/legacy/web_kit_webview_widget_test.dart
@@ -148,7 +148,7 @@
         mockWebViewConfiguration,
         const WKNavigationAction(
           request: request,
-          targetFrame: WKFrameInfo(isMainFrame: false),
+          targetFrame: WKFrameInfo(isMainFrame: false, request: request),
           navigationType: WKNavigationType.linkActivated,
         ),
       );
@@ -1166,7 +1166,9 @@
             mockWebView,
             const WKNavigationAction(
               request: NSUrlRequest(url: 'https://google.com'),
-              targetFrame: WKFrameInfo(isMainFrame: false),
+              targetFrame: WKFrameInfo(
+                  isMainFrame: false,
+                  request: NSUrlRequest(url: 'https://google.com')),
               navigationType: WKNavigationType.linkActivated,
             ),
           ),
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/test/src/web_kit/web_kit_test.dart b/packages/webview_flutter/webview_flutter_wkwebview/test/src/web_kit/web_kit_test.dart
index 2c95a52..e0eeb94 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/test/src/web_kit/web_kit_test.dart
+++ b/packages/webview_flutter/webview_flutter_wkwebview/test/src/web_kit/web_kit_test.dart
@@ -585,7 +585,12 @@
               url: 'url',
               allHttpHeaderFields: <String, String>{},
             ),
-            targetFrame: WKFrameInfoData(isMainFrame: false),
+            targetFrame: WKFrameInfoData(
+                isMainFrame: false,
+                request: NSUrlRequestData(
+                  url: 'url',
+                  allHttpHeaderFields: <String, String>{},
+                )),
             navigationType: WKNavigationType.linkActivated,
           ),
         );
@@ -1004,7 +1009,12 @@
               url: 'url',
               allHttpHeaderFields: <String, String>{},
             ),
-            targetFrame: WKFrameInfoData(isMainFrame: false),
+            targetFrame: WKFrameInfoData(
+                isMainFrame: false,
+                request: NSUrlRequestData(
+                  url: 'url',
+                  allHttpHeaderFields: <String, String>{},
+                )),
             navigationType: WKNavigationType.linkActivated,
           ),
         );
@@ -1063,7 +1073,8 @@
 
         const WKSecurityOrigin origin =
             WKSecurityOrigin(host: 'host', port: 12, protocol: 'protocol');
-        const WKFrameInfo frame = WKFrameInfo(isMainFrame: false);
+        const WKFrameInfo frame =
+            WKFrameInfo(isMainFrame: false, request: NSUrlRequest(url: 'url'));
         const WKMediaCaptureType type = WKMediaCaptureType.microphone;
 
         flutterApi.requestMediaCapturePermission(
@@ -1074,7 +1085,10 @@
             port: origin.port,
             protocol: origin.protocol,
           ),
-          WKFrameInfoData(isMainFrame: frame.isMainFrame),
+          WKFrameInfoData(
+              isMainFrame: frame.isMainFrame,
+              request: NSUrlRequestData(
+                  url: 'url', allHttpHeaderFields: <String, String>{})),
           WKMediaCaptureTypeData(value: type),
         );
 
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/test/webkit_navigation_delegate_test.dart b/packages/webview_flutter/webview_flutter_wkwebview/test/webkit_navigation_delegate_test.dart
index 63d432c..171e405 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/test/webkit_navigation_delegate_test.dart
+++ b/packages/webview_flutter/webview_flutter_wkwebview/test/webkit_navigation_delegate_test.dart
@@ -205,7 +205,9 @@
           WKWebView.detached(),
           const WKNavigationAction(
             request: NSUrlRequest(url: 'https://www.google.com'),
-            targetFrame: WKFrameInfo(isMainFrame: false),
+            targetFrame: WKFrameInfo(
+                isMainFrame: false,
+                request: NSUrlRequest(url: 'https://google.com')),
             navigationType: WKNavigationType.linkActivated,
           ),
         ),
@@ -278,6 +280,9 @@
   CapturingUIDelegate({
     super.onCreateWebView,
     super.requestMediaCapturePermission,
+    super.runJavaScriptAlertDialog,
+    super.runJavaScriptConfirmDialog,
+    super.runJavaScriptTextInputDialog,
     super.instanceManager,
   }) : super.detached() {
     lastCreatedDelegate = this;
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 79f34f3..5bbb36d 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
@@ -91,13 +91,29 @@
               WKFrameInfo frame,
               WKMediaCaptureType type,
             )? requestMediaCapturePermission,
+            Future<void> Function(
+              String message,
+              WKFrameInfo frame,
+            )? runJavaScriptAlertDialog,
+            Future<bool> Function(
+              String message,
+              WKFrameInfo frame,
+            )? runJavaScriptConfirmDialog,
+            Future<String> Function(
+              String prompt,
+              String defaultText,
+              WKFrameInfo frame,
+            )? runJavaScriptTextInputDialog,
             InstanceManager? instanceManager,
           }) {
             return uiDelegate ??
                 CapturingUIDelegate(
-                  onCreateWebView: onCreateWebView,
-                  requestMediaCapturePermission: requestMediaCapturePermission,
-                );
+                    onCreateWebView: onCreateWebView,
+                    requestMediaCapturePermission:
+                        requestMediaCapturePermission,
+                    runJavaScriptAlertDialog: runJavaScriptAlertDialog,
+                    runJavaScriptConfirmDialog: runJavaScriptConfirmDialog,
+                    runJavaScriptTextInputDialog: runJavaScriptTextInputDialog);
           },
           createScriptMessageHandler: WKScriptMessageHandler.detached,
         ),
@@ -999,7 +1015,9 @@
         WKWebViewConfiguration.detached(),
         const WKNavigationAction(
           request: request,
-          targetFrame: WKFrameInfo(isMainFrame: false),
+          targetFrame: WKFrameInfo(
+              isMainFrame: false,
+              request: NSUrlRequest(url: 'https://google.com')),
           navigationType: WKNavigationType.linkActivated,
         ),
       );
@@ -1218,7 +1236,9 @@
         CapturingUIDelegate.lastCreatedDelegate,
         WKWebView.detached(),
         const WKSecurityOrigin(host: '', port: 0, protocol: ''),
-        const WKFrameInfo(isMainFrame: false),
+        const WKFrameInfo(
+            isMainFrame: false,
+            request: NSUrlRequest(url: 'https://google.com')),
         WKMediaCaptureType.microphone,
       );
 
@@ -1228,6 +1248,84 @@
       expect(decision, WKPermissionDecision.grant);
     });
 
+    group('JavaScript Dialog', () {
+      test('setOnJavaScriptAlertDialog', () async {
+        final WebKitWebViewController controller = createControllerWithMocks();
+        late final String message;
+        await controller.setOnJavaScriptAlertDialog(
+            (JavaScriptAlertDialogRequest request) async {
+          message = request.message;
+          return;
+        });
+
+        const String callbackMessage = 'Message';
+        final Future<void> Function(String message, WKFrameInfo frame)
+            onJavaScriptAlertDialog =
+            CapturingUIDelegate.lastCreatedDelegate.runJavaScriptAlertDialog!;
+        await onJavaScriptAlertDialog(
+            callbackMessage,
+            const WKFrameInfo(
+                isMainFrame: false,
+                request: NSUrlRequest(url: 'https://google.com')));
+
+        expect(message, callbackMessage);
+      });
+
+      test('setOnJavaScriptConfirmDialog', () async {
+        final WebKitWebViewController controller = createControllerWithMocks();
+        late final String message;
+        const bool callbackReturnValue = true;
+        await controller.setOnJavaScriptConfirmDialog(
+            (JavaScriptConfirmDialogRequest request) async {
+          message = request.message;
+          return callbackReturnValue;
+        });
+
+        const String callbackMessage = 'Message';
+        final Future<bool> Function(String message, WKFrameInfo frame)
+            onJavaScriptConfirmDialog =
+            CapturingUIDelegate.lastCreatedDelegate.runJavaScriptConfirmDialog!;
+        final bool returnValue = await onJavaScriptConfirmDialog(
+            callbackMessage,
+            const WKFrameInfo(
+                isMainFrame: false,
+                request: NSUrlRequest(url: 'https://google.com')));
+
+        expect(message, callbackMessage);
+        expect(returnValue, callbackReturnValue);
+      });
+
+      test('setOnJavaScriptTextInputDialog', () async {
+        final WebKitWebViewController controller = createControllerWithMocks();
+        late final String message;
+        late final String? defaultText;
+        const String callbackReturnValue = 'Return Value';
+        await controller.setOnJavaScriptTextInputDialog(
+            (JavaScriptTextInputDialogRequest request) async {
+          message = request.message;
+          defaultText = request.defaultText;
+          return callbackReturnValue;
+        });
+
+        const String callbackMessage = 'Message';
+        const String callbackDefaultText = 'Default Text';
+        final Future<String> Function(
+                String prompt, String defaultText, WKFrameInfo frame)
+            onJavaScriptTextInputDialog = CapturingUIDelegate
+                .lastCreatedDelegate.runJavaScriptTextInputDialog!;
+        final String returnValue = await onJavaScriptTextInputDialog(
+            callbackMessage,
+            callbackDefaultText,
+            const WKFrameInfo(
+                isMainFrame: false,
+                request: NSUrlRequest(url: 'https://google.com')));
+
+        expect(message, callbackMessage);
+        expect(defaultText, callbackDefaultText);
+        expect(returnValue, callbackReturnValue);
+      });
+    });
+
     test('inspectable', () async {
       final MockWKWebView mockWebView = MockWKWebView();
 
@@ -1419,6 +1517,9 @@
   CapturingUIDelegate({
     super.onCreateWebView,
     super.requestMediaCapturePermission,
+    super.runJavaScriptAlertDialog,
+    super.runJavaScriptConfirmDialog,
+    super.runJavaScriptTextInputDialog,
     super.instanceManager,
   }) : super.detached() {
     lastCreatedDelegate = this;
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/test/webkit_webview_widget_test.dart b/packages/webview_flutter/webview_flutter_wkwebview/test/webkit_webview_widget_test.dart
index f7bd373..63151eb 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/test/webkit_webview_widget_test.dart
+++ b/packages/webview_flutter/webview_flutter_wkwebview/test/webkit_webview_widget_test.dart
@@ -195,6 +195,9 @@
       }, createUIDelegate: ({
         dynamic onCreateWebView,
         dynamic requestMediaCapturePermission,
+        dynamic runJavaScriptAlertDialog,
+        dynamic runJavaScriptConfirmDialog,
+        dynamic runJavaScriptTextInputDialog,
         InstanceManager? instanceManager,
       }) {
         final MockWKUIDelegate mockWKUIDelegate = MockWKUIDelegate();