Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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.

`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.

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 =
_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