Skip to content

[webview_flutter_wkwebview] Fixes exception from native WKWebViewConfiguration.defaultWebpagePreferences sometimes returning nil #9252

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 5 commits into
base: main
Choose a base branch
from
Draft
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.22.1

* Fixes exception from native `WKWebViewConfiguration.defaultWebpagePreferences` sometimes returning
`nil`.

## 3.22.0

* Adds support to respond to recoverable SSL certificate errors. See `WebKitNavigationDelegate.setOnSSlAuthError`.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,4 +135,17 @@ class WebViewConfigurationProxyAPITests: XCTestCase {

XCTAssertEqual(value, instance.defaultWebpagePreferences)
}

@available(iOS 13.0, macOS 10.15, *)
@MainActor func testSetDefaultWebpagePreferences() {
let registrar = TestProxyApiRegistrar()
let api = registrar.apiDelegate.pigeonApiWKWebViewConfiguration(registrar)

let instance = WKWebViewConfiguration()
let preferences = WKWebpagePreferences()
try? api.pigeonDelegate.setDefaultWebpagePreferences(
pigeonApi: api, pigeonInstance: instance, preferences: preferences)

XCTAssertEqual(instance.defaultWebpagePreferences, preferences)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,14 @@ import XCTest
@testable import webview_flutter_wkwebview

class WebpagePreferencesProxyAPITests: XCTestCase {
func testPigeonDefaultConstructor() {
let registrar = TestProxyApiRegistrar()
let api = registrar.apiDelegate.pigeonApiWKWebpagePreferences(registrar)

let instance = try? api.pigeonDelegate.pigeonDefaultConstructor(pigeonApi: api)
XCTAssertNotNil(instance)
}

@available(iOS 14.0, macOS 11.0, *)
@MainActor func testSetAllowsContentJavaScript() {
let registrar = TestProxyApiRegistrar()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3440,7 +3440,12 @@ protocol PigeonApiDelegateWKWebViewConfiguration {
@available(iOS 13.0.0, macOS 10.15.0, *)
func getDefaultWebpagePreferences(
pigeonApi: PigeonApiWKWebViewConfiguration, pigeonInstance: WKWebViewConfiguration
) throws -> WKWebpagePreferences
) throws -> WKWebpagePreferences?
/// The default preferences to use when loading and rendering content.
@available(iOS 13.0.0, macOS 10.15.0, *)
func setDefaultWebpagePreferences(
pigeonApi: PigeonApiWKWebViewConfiguration, pigeonInstance: WKWebViewConfiguration,
preferences: WKWebpagePreferences) throws
}

protocol PigeonApiProtocolWKWebViewConfiguration {
Expand Down Expand Up @@ -3705,6 +3710,47 @@ final class PigeonApiWKWebViewConfiguration: PigeonApiProtocolWKWebViewConfigura
getDefaultWebpagePreferencesChannel.setMessageHandler(nil)
}
}
if #available(iOS 13.0.0, macOS 10.15.0, *) {
let setDefaultWebpagePreferencesChannel = FlutterBasicMessageChannel(
name:
"dev.flutter.pigeon.webview_flutter_wkwebview.WKWebViewConfiguration.setDefaultWebpagePreferences",
binaryMessenger: binaryMessenger, codec: codec)
if let api = api {
setDefaultWebpagePreferencesChannel.setMessageHandler { message, reply in
let args = message as! [Any?]
let pigeonInstanceArg = args[0] as! WKWebViewConfiguration
let preferencesArg = args[1] as! WKWebpagePreferences
do {
try api.pigeonDelegate.setDefaultWebpagePreferences(
pigeonApi: api, pigeonInstance: pigeonInstanceArg, preferences: preferencesArg)
reply(wrapResult(nil))
} catch {
reply(wrapError(error))
}
}
} else {
setDefaultWebpagePreferencesChannel.setMessageHandler(nil)
}
} else {
let setDefaultWebpagePreferencesChannel = FlutterBasicMessageChannel(
name:
"dev.flutter.pigeon.webview_flutter_wkwebview.WKWebViewConfiguration.setDefaultWebpagePreferences",
binaryMessenger: binaryMessenger, codec: codec)
if api != nil {
setDefaultWebpagePreferencesChannel.setMessageHandler { message, reply in
reply(
wrapError(
FlutterError(
code: "PigeonUnsupportedOperationError",
message:
"Call to setDefaultWebpagePreferences requires @available(iOS 13.0.0, macOS 10.15.0, *).",
details: nil
)))
}
} else {
setDefaultWebpagePreferencesChannel.setMessageHandler(nil)
}
}
}

///Creates a Dart instance of WKWebViewConfiguration and attaches it to [pigeonInstance].
Expand Down Expand Up @@ -7150,6 +7196,10 @@ final class PigeonApiURL: PigeonApiProtocolURL {
}
}
protocol PigeonApiDelegateWKWebpagePreferences {
/// Creates a `WKWebpagePreferences`.
@available(iOS 13.0.0, macOS 10.15.0, *)
func pigeonDefaultConstructor(pigeonApi: PigeonApiWKWebpagePreferences) throws
-> WKWebpagePreferences
/// A Boolean value that indicates whether JavaScript from web content is
/// allowed to run.
@available(iOS 13.0.0, macOS 10.15.0, *)
Expand Down Expand Up @@ -7185,6 +7235,47 @@ final class PigeonApiWKWebpagePreferences: PigeonApiProtocolWKWebpagePreferences
readerWriter: WebKitLibraryPigeonInternalProxyApiCodecReaderWriter(
pigeonRegistrar: api!.pigeonRegistrar))
: FlutterStandardMessageCodec.sharedInstance()
if #available(iOS 13.0.0, macOS 10.15.0, *) {
let pigeonDefaultConstructorChannel = FlutterBasicMessageChannel(
name:
"dev.flutter.pigeon.webview_flutter_wkwebview.WKWebpagePreferences.pigeon_defaultConstructor",
binaryMessenger: binaryMessenger, codec: codec)
if let api = api {
pigeonDefaultConstructorChannel.setMessageHandler { message, reply in
let args = message as! [Any?]
let pigeonIdentifierArg = args[0] as! Int64
do {
api.pigeonRegistrar.instanceManager.addDartCreatedInstance(
try api.pigeonDelegate.pigeonDefaultConstructor(pigeonApi: api),
withIdentifier: pigeonIdentifierArg)
reply(wrapResult(nil))
} catch {
reply(wrapError(error))
}
}
} else {
pigeonDefaultConstructorChannel.setMessageHandler(nil)
}
} else {
let pigeonDefaultConstructorChannel = FlutterBasicMessageChannel(
name:
"dev.flutter.pigeon.webview_flutter_wkwebview.WKWebpagePreferences.pigeon_defaultConstructor",
binaryMessenger: binaryMessenger, codec: codec)
if api != nil {
pigeonDefaultConstructorChannel.setMessageHandler { message, reply in
reply(
wrapError(
FlutterError(
code: "PigeonUnsupportedOperationError",
message:
"Call to pigeonDefaultConstructor requires @available(iOS 13.0.0, macOS 10.15.0, *).",
details: nil
)))
}
} else {
pigeonDefaultConstructorChannel.setMessageHandler(nil)
}
}
if #available(iOS 13.0.0, macOS 10.15.0, *) {
let setAllowsContentJavaScriptChannel = FlutterBasicMessageChannel(
name:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,15 @@ class WebViewConfigurationProxyAPIDelegate: PigeonApiDelegateWKWebViewConfigurat
@available(iOS 13.0, macOS 10.15, *)
func getDefaultWebpagePreferences(
pigeonApi: PigeonApiWKWebViewConfiguration, pigeonInstance: WKWebViewConfiguration
) throws -> WKWebpagePreferences {
) throws -> WKWebpagePreferences? {
return pigeonInstance.defaultWebpagePreferences
}

@available(iOS 13.0, macOS 10.15, *)
func setDefaultWebpagePreferences(
pigeonApi: PigeonApiWKWebViewConfiguration, pigeonInstance: WKWebViewConfiguration,
preferences: WKWebpagePreferences
) throws {
pigeonInstance.defaultWebpagePreferences = preferences
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,13 @@ import WebKit
/// This class may handle instantiating native object instances that are attached to a Dart instance
/// or handle method calls on the associated native class or an instance of that class.
class WebpagePreferencesProxyAPIDelegate: PigeonApiDelegateWKWebpagePreferences {
@available(iOS 13.0, macOS 10.15, *)
func pigeonDefaultConstructor(pigeonApi: PigeonApiWKWebpagePreferences) throws
-> WKWebpagePreferences
{
return WKWebpagePreferences()
}

@available(iOS 13.0, macOS 10.15, *)
func setAllowsContentJavaScript(
pigeonApi: PigeonApiWKWebpagePreferences, pigeonInstance: WKWebpagePreferences, allow: Bool
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3698,7 +3698,7 @@ class WKWebViewConfiguration extends NSObject {
}

/// The default preferences to use when loading and rendering content.
Future<WKWebpagePreferences> getDefaultWebpagePreferences() async {
Future<WKWebpagePreferences?> getDefaultWebpagePreferences() async {
final _PigeonInternalProxyApiBaseCodec pigeonChannelCodec =
_pigeonVar_codecWKWebViewConfiguration;
final BinaryMessenger? pigeonVar_binaryMessenger = pigeon_binaryMessenger;
Expand All @@ -3722,13 +3722,39 @@ class WKWebViewConfiguration extends NSObject {
message: pigeonVar_replyList[1] as String?,
details: pigeonVar_replyList[2],
);
} else if (pigeonVar_replyList[0] == null) {
} else {
return (pigeonVar_replyList[0] as WKWebpagePreferences?);
}
}

/// The default preferences to use when loading and rendering content.
Future<void> setDefaultWebpagePreferences(
WKWebpagePreferences preferences) async {
final _PigeonInternalProxyApiBaseCodec pigeonChannelCodec =
_pigeonVar_codecWKWebViewConfiguration;
final BinaryMessenger? pigeonVar_binaryMessenger = pigeon_binaryMessenger;
const String pigeonVar_channelName =
'dev.flutter.pigeon.webview_flutter_wkwebview.WKWebViewConfiguration.setDefaultWebpagePreferences';
final BasicMessageChannel<Object?> pigeonVar_channel =
BasicMessageChannel<Object?>(
pigeonVar_channelName,
pigeonChannelCodec,
binaryMessenger: pigeonVar_binaryMessenger,
);
final Future<Object?> pigeonVar_sendFuture =
pigeonVar_channel.send(<Object?>[this, preferences]);
final List<Object?>? 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: 'null-error',
message: 'Host platform returned null value for non-null return value.',
code: pigeonVar_replyList[0]! as String,
message: pigeonVar_replyList[1] as String?,
details: pigeonVar_replyList[2],
);
} else {
return (pigeonVar_replyList[0] as WKWebpagePreferences?)!;
return;
}
}

Expand Down Expand Up @@ -8202,6 +8228,44 @@ class URL extends NSObject {
///
/// See https://developer.apple.com/documentation/webkit/wkwebpagepreferences.
class WKWebpagePreferences extends NSObject {
/// Creates a `WKWebpagePreferences`.
WKWebpagePreferences({
super.pigeon_binaryMessenger,
super.pigeon_instanceManager,
super.observeValue,
}) : super.pigeon_detached() {
final int pigeonVar_instanceIdentifier =
pigeon_instanceManager.addDartCreatedInstance(this);
final _PigeonInternalProxyApiBaseCodec pigeonChannelCodec =
_pigeonVar_codecWKWebpagePreferences;
final BinaryMessenger? pigeonVar_binaryMessenger = pigeon_binaryMessenger;
const String pigeonVar_channelName =
'dev.flutter.pigeon.webview_flutter_wkwebview.WKWebpagePreferences.pigeon_defaultConstructor';
final BasicMessageChannel<Object?> pigeonVar_channel =
BasicMessageChannel<Object?>(
pigeonVar_channelName,
pigeonChannelCodec,
binaryMessenger: pigeonVar_binaryMessenger,
);
final Future<Object?> pigeonVar_sendFuture =
pigeonVar_channel.send(<Object?>[pigeonVar_instanceIdentifier]);
() async {
final List<Object?>? 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;
}
}();
}

/// Constructs [WKWebpagePreferences] without creating the associated native object.
///
/// This should only be used by subclasses created by this library or to
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -512,8 +512,14 @@ class WebKitWebViewPlatformController extends WebViewPlatformController {
Future<void> _setJavaScriptMode(JavascriptMode mode) async {
// Attempt to set the value that requires iOS 14+.
try {
final WKWebpagePreferences webpagePreferences =
WKWebpagePreferences? webpagePreferences =
await webView.configuration.getDefaultWebpagePreferences();
if (webpagePreferences == null) {
webpagePreferences = webViewProxy.createWebpagePreferences();
unawaited(webView.configuration.setDefaultWebpagePreferences(
webpagePreferences,
));
}
switch (mode) {
case JavascriptMode.disabled:
await webpagePreferences.setAllowsContentJavaScript(false);
Expand Down Expand Up @@ -769,4 +775,9 @@ class WebViewWidgetProxy {
didReceiveAuthenticationChallenge: didReceiveAuthenticationChallenge,
);
}

/// Constructs a [WKWebpagePreferences].
WKWebpagePreferences createWebpagePreferences() {
return WKWebpagePreferences();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ class WebKitProxy {
this.newPlatformWebView = PlatformWebView.new,
this.newWKUIDelegate = WKUIDelegate.new,
this.newUIScrollViewDelegate = UIScrollViewDelegate.new,
this.newWKWebpagePreferences = WKWebpagePreferences.new,
this.createAsyncAuthenticationChallengeResponse =
AuthenticationChallengeResponse.createAsync,
this.withUserAsyncURLCredential = URLCredential.withUserAsync,
Expand Down Expand Up @@ -187,6 +188,9 @@ class WebKitProxy {
)? scrollViewDidScroll,
}) newUIScrollViewDelegate;

/// Constructs [WKWebpagePreferences].
final WKWebpagePreferences Function() newWKWebpagePreferences;

/// Calls to [AuthenticationChallengeResponse.createAsync].
final Future<AuthenticationChallengeResponse> Function(
UrlSessionAuthChallengeDisposition disposition,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -619,8 +619,15 @@ class WebKitWebViewController extends PlatformWebViewController {
Future<void> setJavaScriptMode(JavaScriptMode javaScriptMode) async {
// Attempt to set the value that requires iOS 14+.
try {
final WKWebpagePreferences webpagePreferences =
WKWebpagePreferences? webpagePreferences =
await _webView.configuration.getDefaultWebpagePreferences();
if (webpagePreferences == null) {
webpagePreferences =
_webKitParams.webKitProxy.newWKWebpagePreferences();
unawaited(_webView.configuration.setDefaultWebpagePreferences(
webpagePreferences,
));
}
switch (javaScriptMode) {
case JavaScriptMode.disabled:
await webpagePreferences.setAllowsContentJavaScript(false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -711,7 +711,10 @@ abstract class WKWebViewConfiguration extends NSObject {
void setMediaTypesRequiringUserActionForPlayback(AudiovisualMediaType type);

/// The default preferences to use when loading and rendering content.
WKWebpagePreferences getDefaultWebpagePreferences();
WKWebpagePreferences? getDefaultWebpagePreferences();

/// The default preferences to use when loading and rendering content.
void setDefaultWebpagePreferences(WKWebpagePreferences preferences);
}

/// An object for managing interactions between JavaScript code and your web
Expand Down Expand Up @@ -1213,6 +1216,9 @@ abstract class URL extends NSObject {
),
)
abstract class WKWebpagePreferences extends NSObject {
/// Creates a `WKWebpagePreferences`.
WKWebpagePreferences();

/// A Boolean value that indicates whether JavaScript from web content is
/// allowed to run.
void setAllowsContentJavaScript(bool allow);
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.22.0
version: 3.22.1

environment:
sdk: ^3.5.0
Expand Down
Loading