Skip to content
Open
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
85e36de
[webview_flutter_wkwebview] Add support for javaScriptCanOpenWindowsA…
fummicc1 Dec 11, 2025
767e4a5
Format Swift and Dart files
fummicc1 Dec 12, 2025
b58764b
Merge branch 'main' into add-support-for-javaScriptCanOpenWindowsAuto…
fummicc1 Dec 14, 2025
bd3b12f
Bump version to 3.24.0 for javaScriptCanOpenWindowsAutomatically feature
fummicc1 Dec 15, 2025
4133b20
Make javaScriptCanOpenWindowsAutomatically nullable to respect platfo…
fummicc1 Dec 15, 2025
58ecb77
Remove failable `try` to improve test reliability. Updates the docume…
fummicc1 Dec 15, 2025
9dde6ef
Merge branch 'main' into add-support-for-javaScriptCanOpenWindowsAuto…
fummicc1 Dec 22, 2025
91f96b3
Merge branch 'main' into add-support-for-javaScriptCanOpenWindowsAuto…
fummicc1 Jan 9, 2026
b5785c7
Format dart code of webview_flutter_wkwebview package.
fummicc1 Jan 9, 2026
a700da7
Merge branch 'main' into add-support-for-javaScriptCanOpenWindowsAuto…
fummicc1 Jan 31, 2026
ec04126
Merge branch 'main' into add-support-for-javaScriptCanOpenWindowsAuto…
fummicc1 Feb 9, 2026
cf4f2c9
Refactor: remove duplicate javaScriptCanOpenWindowsAutomatically logi…
fummicc1 Feb 9, 2026
0d1533c
Apply formatter
fummicc1 Feb 11, 2026
f630604
Consolidate javaScriptCanOpenWindowsAutomatically documentation
fummicc1 Feb 11, 2026
7df6f3e
Add explicit namespace of WebKitWebViewControllerCreationParams in `C…
fummicc1 Feb 11, 2026
130f1c7
Merge branch 'main' of github.com:flutter/packages into add-support-f…
bparrishMines Feb 23, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
## 3.24.0

* Adds support for `javaScriptCanOpenWindowsAutomatically` to allow JavaScript's
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

uber nit: maybe
WebKitWebViewControllerCreationParams.javaScriptCanOpenWindowsAutomatically so the reader doesn't have to look for the exact name space.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@LongCatIsLooong

Thanks for your view.

Fixed in bcd1d03.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm sorry for the confusion but above commit is outdated.
I fixed it again in 7df6f3e

`window.open()` to work without user interaction on iOS and macOS.

## 3.23.5

* Removes internal native library Dart proxy.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -170,11 +170,12 @@ class TestNavigationDelegateApi: PigeonApiProtocolWKNavigationDelegate {
func decidePolicyForNavigationAction(
pigeonInstance pigeonInstanceArg: WKNavigationDelegate, webView webViewArg: WKWebView,
navigationAction navigationActionArg: WKNavigationAction,
completion: @escaping (
Result<
webview_flutter_wkwebview.NavigationActionPolicy, webview_flutter_wkwebview.PigeonError
>
) -> Void
completion:
@escaping (
Result<
webview_flutter_wkwebview.NavigationActionPolicy, webview_flutter_wkwebview.PigeonError
>
) -> Void
) {
decidePolicyForNavigationActionArgs = [webViewArg, navigationActionArg]
completion(.success(.allow))
Expand All @@ -183,11 +184,12 @@ class TestNavigationDelegateApi: PigeonApiProtocolWKNavigationDelegate {
func decidePolicyForNavigationResponse(
pigeonInstance pigeonInstanceArg: WKNavigationDelegate, webView webViewArg: WKWebView,
navigationResponse navigationResponseArg: WKNavigationResponse,
completion: @escaping (
Result<
webview_flutter_wkwebview.NavigationResponsePolicy, webview_flutter_wkwebview.PigeonError
>
) -> Void
completion:
@escaping (
Result<
webview_flutter_wkwebview.NavigationResponsePolicy, webview_flutter_wkwebview.PigeonError
>
) -> Void
) {
decidePolicyForNavigationResponseArgs = [webViewArg, navigationResponseArg]
completion(.success(.cancel))
Expand Down Expand Up @@ -219,12 +221,13 @@ class TestNavigationDelegateApi: PigeonApiProtocolWKNavigationDelegate {
func didReceiveAuthenticationChallenge(
pigeonInstance pigeonInstanceArg: WKNavigationDelegate, webView webViewArg: WKWebView,
challenge challengeArg: URLAuthenticationChallenge,
completion: @escaping (
Result<
webview_flutter_wkwebview.AuthenticationChallengeResponse,
webview_flutter_wkwebview.PigeonError
>
) -> Void
completion:
@escaping (
Result<
webview_flutter_wkwebview.AuthenticationChallengeResponse,
webview_flutter_wkwebview.PigeonError
>
) -> Void
) {
didReceiveAuthenticationChallengeArgs = [webViewArg, challengeArg]
completion(
Expand All @@ -241,7 +244,8 @@ class TestWebView: WKWebView {
}
}

class TestURLAuthenticationChallengeSender: NSObject, URLAuthenticationChallengeSender, @unchecked
class TestURLAuthenticationChallengeSender: NSObject, URLAuthenticationChallengeSender,
@unchecked
Sendable
{
func use(_ credential: URLCredential, for challenge: URLAuthenticationChallenge) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,16 @@ class PreferencesProxyAPITests: XCTestCase {
XCTAssertEqual(instance.javaScriptEnabled, enabled)
}
}

@MainActor func testSetJavaScriptCanOpenWindowsAutomatically() throws {
let registrar = TestProxyApiRegistrar()
let api = registrar.apiDelegate.pigeonApiWKPreferences(registrar)

let instance = WKPreferences()
let enabled = true
try api.pigeonDelegate.setJavaScriptCanOpenWindowsAutomatically(
pigeonApi: api, pigeonInstance: instance, enabled: enabled)

XCTAssertEqual(instance.javaScriptCanOpenWindowsAutomatically, enabled)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,8 @@ public class NavigationDelegateImpl: NSObject, WKNavigationDelegate {
#if compiler(>=6.0)
public func webView(
_ webView: WKWebView, didReceive challenge: URLAuthenticationChallenge,
completionHandler: @escaping @MainActor (URLSession.AuthChallengeDisposition, URLCredential?)
completionHandler:
@escaping @MainActor (URLSession.AuthChallengeDisposition, URLCredential?)
->
Void
) {
Expand All @@ -256,7 +257,8 @@ public class NavigationDelegateImpl: NSObject, WKNavigationDelegate {
#else
public func webView(
_ webView: WKWebView, didReceive challenge: URLAuthenticationChallenge,
completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) ->
completionHandler:
@escaping (URLSession.AuthChallengeDisposition, URLCredential?) ->
Void
) {
registrar.dispatchOnMainThread { onFailure in
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,10 @@ class PreferencesProxyAPIDelegate: PigeonApiDelegateWKPreferences {
pigeonInstance.javaScriptEnabled = enabled
}
}

func setJavaScriptCanOpenWindowsAutomatically(
pigeonApi: PigeonApiWKPreferences, pigeonInstance: WKPreferences, enabled: Bool
) throws {
pigeonInstance.javaScriptCanOpenWindowsAutomatically = enabled
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,10 @@ open class ProxyAPIRegistrar: WebKitLibraryPigeonProxyApiRegistrar {

/// Handles calling a Flutter method on the main thread.
func dispatchOnMainThread(
execute work: @escaping (
_ onFailure: @escaping (_ methodName: String, _ error: PigeonError) -> Void
) -> Void
execute work:
@escaping (
_ onFailure: @escaping (_ methodName: String, _ error: PigeonError) -> Void
) -> Void
) {
DispatchQueue.main.async {
work { methodName, error in
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3917,6 +3917,15 @@ protocol PigeonApiDelegateWKPreferences {
/// A Boolean value that indicates whether JavaScript is enabled.
func setJavaScriptEnabled(
pigeonApi: PigeonApiWKPreferences, pigeonInstance: WKPreferences, enabled: Bool) throws
/// A Boolean value that indicates whether JavaScript can open windows without user interaction.
///
/// The default value is `false` on iOS and `true` on macOS.
/// Set to `true` to allow JavaScript to open windows automatically
/// through `window.open()` calls without requiring user gestures.
///
/// See https://developer.apple.com/documentation/webkit/wkpreferences/javascriptcanopenwindowsautomatically
func setJavaScriptCanOpenWindowsAutomatically(
pigeonApi: PigeonApiWKPreferences, pigeonInstance: WKPreferences, enabled: Bool) throws
}

protocol PigeonApiProtocolWKPreferences {
Expand Down Expand Up @@ -3964,6 +3973,26 @@ final class PigeonApiWKPreferences: PigeonApiProtocolWKPreferences {
} else {
setJavaScriptEnabledChannel.setMessageHandler(nil)
}
let setJavaScriptCanOpenWindowsAutomaticallyChannel = FlutterBasicMessageChannel(
name:
"dev.flutter.pigeon.webview_flutter_wkwebview.WKPreferences.setJavaScriptCanOpenWindowsAutomatically",
binaryMessenger: binaryMessenger, codec: codec)
if let api = api {
setJavaScriptCanOpenWindowsAutomaticallyChannel.setMessageHandler { message, reply in
let args = message as! [Any?]
let pigeonInstanceArg = args[0] as! WKPreferences
let enabledArg = args[1] as! Bool
do {
try api.pigeonDelegate.setJavaScriptCanOpenWindowsAutomatically(
pigeonApi: api, pigeonInstance: pigeonInstanceArg, enabled: enabledArg)
reply(wrapResult(nil))
} catch {
reply(wrapError(error))
}
}
} else {
setJavaScriptCanOpenWindowsAutomaticallyChannel.setMessageHandler(nil)
}
}

///Creates a Dart instance of WKPreferences and attaches it to [pigeonInstance].
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4687,6 +4687,41 @@ class WKPreferences extends NSObject {
}
}

/// A Boolean value that indicates whether JavaScript can open windows without user interaction.
///
/// The default value is `false` on iOS and `true` on macOS.
/// Set to `true` to allow JavaScript to open windows automatically
/// through `window.open()` calls without requiring user gestures.
///
/// See https://developer.apple.com/documentation/webkit/wkpreferences/javascriptcanopenwindowsautomatically
Future<void> setJavaScriptCanOpenWindowsAutomatically(bool enabled) async {
final _PigeonInternalProxyApiBaseCodec pigeonChannelCodec =
_pigeonVar_codecWKPreferences;
final BinaryMessenger? pigeonVar_binaryMessenger = pigeon_binaryMessenger;
const pigeonVar_channelName =
'dev.flutter.pigeon.webview_flutter_wkwebview.WKPreferences.setJavaScriptCanOpenWindowsAutomatically';
final pigeonVar_channel = BasicMessageChannel<Object?>(
pigeonVar_channelName,
pigeonChannelCodec,
binaryMessenger: pigeonVar_binaryMessenger,
);
final Future<Object?> pigeonVar_sendFuture = pigeonVar_channel.send(
<Object?>[this, enabled],
);
final pigeonVar_replyList = await pigeonVar_sendFuture as List<Object?>?;
if (pigeonVar_replyList == null) {
throw _createConnectionError(pigeonVar_channelName);
} else if (pigeonVar_replyList.length > 1) {
throw PlatformException(
code: pigeonVar_replyList[0]! as String,
message: pigeonVar_replyList[1] as String?,
details: pigeonVar_replyList[2],
);
} else {
return;
}
}

@override
WKPreferences pigeon_copy() {
return WKPreferences.pigeon_detached(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ class WebKitWebViewControllerCreationParams
},
this.allowsInlineMediaPlayback = false,
this.limitsNavigationsToAppBoundDomains = false,
this.javaScriptCanOpenWindowsAutomatically,
}) {
_configuration = WKWebViewConfiguration();

Expand Down Expand Up @@ -122,10 +123,13 @@ class WebKitWebViewControllerCreationParams
},
bool allowsInlineMediaPlayback = false,
bool limitsNavigationsToAppBoundDomains = false,
bool? javaScriptCanOpenWindowsAutomatically,
}) : this(
mediaTypesRequiringUserAction: mediaTypesRequiringUserAction,
allowsInlineMediaPlayback: allowsInlineMediaPlayback,
limitsNavigationsToAppBoundDomains: limitsNavigationsToAppBoundDomains,
javaScriptCanOpenWindowsAutomatically:
javaScriptCanOpenWindowsAutomatically,
);

late final WKWebViewConfiguration _configuration;
Expand All @@ -147,6 +151,18 @@ class WebKitWebViewControllerCreationParams
/// (Only available for iOS > 14.0)
/// Defaults to false.
final bool limitsNavigationsToAppBoundDomains;

/// Whether JavaScript can open windows without user interaction.
///
/// Setting this to `true` allows JavaScript's `window.open()` to create
/// new windows automatically without requiring a user gesture.
///
/// When `null`, the platform's native default is used:
/// - iOS: `false`
/// - macOS: `true`
///
/// See https://developer.apple.com/documentation/webkit/wkpreferences/1536573-javascriptcanopenwindowsautomati
Copy link
Contributor

@LongCatIsLooong LongCatIsLooong Dec 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit, the link doesn't seem to be complete (although the website does seem to redirect you to the correct page). Also I doubt this will be rendered as a link in markdown (so people would have to copy and paste this into their browser's URL bar in order to open it).

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 96e2b0a.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I reviewed doc comment again and refined in f630604.

final bool? javaScriptCanOpenWindowsAutomatically;
}

/// An implementation of [PlatformWebViewController] with the WebKit api.
Expand Down Expand Up @@ -643,6 +659,16 @@ class WebKitWebViewController extends PlatformWebViewController {
case JavaScriptMode.unrestricted:
await webpagePreferences.setAllowsContentJavaScript(true);
}
// Set javaScriptCanOpenWindowsAutomatically on WKPreferences only if explicitly set
final bool? javaScriptCanOpenWindowsAutomatically =
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit:

You should be able to move this code above the try block as to not have duplicate code.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you so much.
I fixed it in cf4f2c9.

_webKitParams.javaScriptCanOpenWindowsAutomatically;
if (javaScriptCanOpenWindowsAutomatically != null) {
final WKPreferences preferences = await _webView.configuration
.getPreferences();
await preferences.setJavaScriptCanOpenWindowsAutomatically(
javaScriptCanOpenWindowsAutomatically,
);
}
return;
} on PlatformException catch (exception) {
if (exception.code != 'PigeonUnsupportedOperationError') {
Expand All @@ -660,6 +686,13 @@ class WebKitWebViewController extends PlatformWebViewController {
case JavaScriptMode.unrestricted:
await preferences.setJavaScriptEnabled(true);
}
final bool? javaScriptCanOpenWindowsAutomatically =
_webKitParams.javaScriptCanOpenWindowsAutomatically;
if (javaScriptCanOpenWindowsAutomatically != null) {
await preferences.setJavaScriptCanOpenWindowsAutomatically(
javaScriptCanOpenWindowsAutomatically,
);
}
}

@override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -747,6 +747,15 @@ abstract class WKUserContentController extends NSObject {
abstract class WKPreferences extends NSObject {
/// A Boolean value that indicates whether JavaScript is enabled.
void setJavaScriptEnabled(bool enabled);

/// A Boolean value that indicates whether JavaScript can open windows without user interaction.
///
/// The default value is `false` on iOS and `true` on macOS.
/// Set to `true` to allow JavaScript to open windows automatically
/// through `window.open()` calls without requiring user gestures.
///
/// See https://developer.apple.com/documentation/webkit/wkpreferences/javascriptcanopenwindowsautomatically
void setJavaScriptCanOpenWindowsAutomatically(bool enabled);
}

/// An interface for receiving messages from JavaScript code running in a webpage.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: webview_flutter_wkwebview
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.23.5
version: 3.24.0

environment:
sdk: ^3.9.0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -565,6 +565,17 @@ class MockWKPreferences extends _i1.Mock implements _i2.WKPreferences {
)
as _i4.Future<void>);

@override
_i4.Future<void> setJavaScriptCanOpenWindowsAutomatically(bool? enabled) =>
(super.noSuchMethod(
Invocation.method(#setJavaScriptCanOpenWindowsAutomatically, [
enabled,
]),
returnValue: _i4.Future<void>.value(),
returnValueForMissingStub: _i4.Future<void>.value(),
)
as _i4.Future<void>);

@override
_i2.WKPreferences pigeon_copy() =>
(super.noSuchMethod(
Expand Down
Loading