Skip to content

Commit f7a4e5d

Browse files
[webview_flutter_wkwebview] Fixes crash with nil WKFrameInfo.request (#8766)
I manually verified with the example provided in the issue below that the `WKFrameInfo.request` also returns nil with the old Objective-C implementation. This crash seems to be caused by the Swift code crashing when it encounters a nil value that should be nonnull. Fixes flutter/flutter#163549
1 parent dfaf90b commit f7a4e5d

File tree

8 files changed

+73
-21
lines changed

8 files changed

+73
-21
lines changed

packages/webview_flutter/webview_flutter_wkwebview/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 3.18.4
2+
3+
* Fixes crash when native `WKFrameInfo.request` is nil.
4+
15
## 3.18.3
26

37
* Fixes crash where the native `AuthenticationChallengeResponse` could not be found for auth

packages/webview_flutter/webview_flutter_wkwebview/darwin/Tests/FrameInfoProxyAPITests.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,16 @@ class FrameInfoProxyAPITests: XCTestCase {
2828

2929
XCTAssertEqual(value?.value, instance!.request)
3030
}
31+
32+
@MainActor func testNilRequest() {
33+
let registrar = TestProxyApiRegistrar()
34+
let api = registrar.apiDelegate.pigeonApiWKFrameInfo(registrar)
35+
36+
let instance = TestFrameInfoWithNilRequest()
37+
let value = try? api.pigeonDelegate.request(pigeonApi: api, pigeonInstance: instance)
38+
39+
XCTAssertNil(value)
40+
}
3141
}
3242

3343
class TestFrameInfo: WKFrameInfo {
@@ -39,3 +49,6 @@ class TestFrameInfo: WKFrameInfo {
3949
return URLRequest(url: URL(string: "https://google.com")!)
4050
}
4151
}
52+
53+
class TestFrameInfoWithNilRequest: WKFrameInfo {
54+
}

packages/webview_flutter/webview_flutter_wkwebview/darwin/webview_flutter_wkwebview/Sources/webview_flutter_wkwebview/FrameInfoProxyAPIDelegate.swift

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,18 @@
44

55
import WebKit
66

7+
extension WKFrameInfo {
8+
// It's possible that `WKFrameInfo.request` can be a nil value despite the Swift code considering
9+
// it to be nonnull. This causes a crash when accessing the value with Swift. Accessing the value
10+
// this way prevents the crash when the value is nil.
11+
//
12+
// See https://github.com/flutter/flutter/issues/163549 and https://developer.apple.com/forums/thread/77888.
13+
var maybeRequest: URLRequest? {
14+
return self.perform(#selector(getter:WKFrameInfo.request))?.takeUnretainedValue()
15+
as! URLRequest?
16+
}
17+
}
18+
719
/// ProxyApi implementation for `WKFrameInfo`.
820
///
921
/// This class may handle instantiating native object instances that are attached to a Dart instance
@@ -14,8 +26,12 @@ class FrameInfoProxyAPIDelegate: PigeonApiDelegateWKFrameInfo {
1426
}
1527

1628
func request(pigeonApi: PigeonApiWKFrameInfo, pigeonInstance: WKFrameInfo) throws
17-
-> URLRequestWrapper
29+
-> URLRequestWrapper?
1830
{
19-
return URLRequestWrapper(pigeonInstance.request)
31+
let request = pigeonInstance.maybeRequest
32+
if let request = request {
33+
return URLRequestWrapper(request)
34+
}
35+
return nil
2036
}
2137
}

packages/webview_flutter/webview_flutter_wkwebview/darwin/webview_flutter_wkwebview/Sources/webview_flutter_wkwebview/WebKitLibrary.g.swift

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2125,7 +2125,7 @@ protocol PigeonApiDelegateWKFrameInfo {
21252125
func isMainFrame(pigeonApi: PigeonApiWKFrameInfo, pigeonInstance: WKFrameInfo) throws -> Bool
21262126
/// The frame’s current request.
21272127
func request(pigeonApi: PigeonApiWKFrameInfo, pigeonInstance: WKFrameInfo) throws
2128-
-> URLRequestWrapper
2128+
-> URLRequestWrapper?
21292129
}
21302130

21312131
protocol PigeonApiProtocolWKFrameInfo {
@@ -3993,8 +3993,15 @@ protocol PigeonApiProtocolWKNavigationDelegate {
39933993
completion: @escaping (Result<Void, PigeonError>) -> Void)
39943994
/// Asks the delegate to respond to an authentication challenge.
39953995
///
3996-
/// Returns a List with a `UrlSessionAuthChallengeDisposition` and a nullable
3997-
/// `URLCredential`.
3996+
/// This return value expects a List with:
3997+
///
3998+
/// 1. `UrlSessionAuthChallengeDisposition`
3999+
/// 2. A nullable map to instantiate a `URLCredential`. The map structure is
4000+
/// [
4001+
/// "user": "<nonnull String username>",
4002+
/// "password": "<nonnull String user password>",
4003+
/// "persistence": <nonnull enum value of `UrlCredentialPersistence`>,
4004+
/// ]
39984005
func didReceiveAuthenticationChallenge(
39994006
pigeonInstance pigeonInstanceArg: WKNavigationDelegate, webView webViewArg: WKWebView,
40004007
challenge challengeArg: URLAuthenticationChallenge,
@@ -4337,8 +4344,15 @@ final class PigeonApiWKNavigationDelegate: PigeonApiProtocolWKNavigationDelegate
43374344

43384345
/// Asks the delegate to respond to an authentication challenge.
43394346
///
4340-
/// Returns a List with a `UrlSessionAuthChallengeDisposition` and a nullable
4341-
/// `URLCredential`.
4347+
/// This return value expects a List with:
4348+
///
4349+
/// 1. `UrlSessionAuthChallengeDisposition`
4350+
/// 2. A nullable map to instantiate a `URLCredential`. The map structure is
4351+
/// [
4352+
/// "user": "<nonnull String username>",
4353+
/// "password": "<nonnull String user password>",
4354+
/// "persistence": <nonnull enum value of `UrlCredentialPersistence`>,
4355+
/// ]
43424356
func didReceiveAuthenticationChallenge(
43434357
pigeonInstance pigeonInstanceArg: WKNavigationDelegate, webView webViewArg: WKWebView,
43444358
challenge challengeArg: URLAuthenticationChallenge,

packages/webview_flutter/webview_flutter_wkwebview/lib/src/common/web_kit.g.dart

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1756,7 +1756,7 @@ class WKFrameInfo extends NSObject {
17561756
super.pigeon_binaryMessenger,
17571757
super.pigeon_instanceManager,
17581758
required this.isMainFrame,
1759-
required this.request,
1759+
this.request,
17601760
super.observeValue,
17611761
}) : super.pigeon_detached();
17621762

@@ -1765,15 +1765,15 @@ class WKFrameInfo extends NSObject {
17651765
final bool isMainFrame;
17661766

17671767
/// The frame’s current request.
1768-
final URLRequest request;
1768+
final URLRequest? request;
17691769

17701770
static void pigeon_setUpMessageHandlers({
17711771
bool pigeon_clearHandlers = false,
17721772
BinaryMessenger? pigeon_binaryMessenger,
17731773
PigeonInstanceManager? pigeon_instanceManager,
17741774
WKFrameInfo Function(
17751775
bool isMainFrame,
1776-
URLRequest request,
1776+
URLRequest? request,
17771777
)? pigeon_newInstance,
17781778
}) {
17791779
final _PigeonInternalProxyApiBaseCodec pigeonChannelCodec =
@@ -1801,17 +1801,15 @@ class WKFrameInfo extends NSObject {
18011801
assert(arg_isMainFrame != null,
18021802
'Argument for dev.flutter.pigeon.webview_flutter_wkwebview.WKFrameInfo.pigeon_newInstance was null, expected non-null bool.');
18031803
final URLRequest? arg_request = (args[2] as URLRequest?);
1804-
assert(arg_request != null,
1805-
'Argument for dev.flutter.pigeon.webview_flutter_wkwebview.WKFrameInfo.pigeon_newInstance was null, expected non-null URLRequest.');
18061804
try {
18071805
(pigeon_instanceManager ?? PigeonInstanceManager.instance)
18081806
.addHostCreatedInstance(
1809-
pigeon_newInstance?.call(arg_isMainFrame!, arg_request!) ??
1807+
pigeon_newInstance?.call(arg_isMainFrame!, arg_request) ??
18101808
WKFrameInfo.pigeon_detached(
18111809
pigeon_binaryMessenger: pigeon_binaryMessenger,
18121810
pigeon_instanceManager: pigeon_instanceManager,
18131811
isMainFrame: arg_isMainFrame!,
1814-
request: arg_request!,
1812+
request: arg_request,
18151813
),
18161814
arg_pigeon_instanceIdentifier!,
18171815
);
@@ -4326,8 +4324,15 @@ class WKNavigationDelegate extends NSObject {
43264324

43274325
/// Asks the delegate to respond to an authentication challenge.
43284326
///
4329-
/// Returns a List with a `UrlSessionAuthChallengeDisposition` and a nullable
4330-
/// `URLCredential`.
4327+
/// This return value expects a List with:
4328+
///
4329+
/// 1. `UrlSessionAuthChallengeDisposition`
4330+
/// 2. A nullable map to instantiate a `URLCredential`. The map structure is
4331+
/// [
4332+
/// "user": "<nonnull String username>",
4333+
/// "password": "<nonnull String user password>",
4334+
/// "persistence": <nonnull enum value of `UrlCredentialPersistence`>,
4335+
/// ]
43314336
///
43324337
/// For the associated Native object to be automatically garbage collected,
43334338
/// it is required that the implementation of this `Function` doesn't have a

packages/webview_flutter/webview_flutter_wkwebview/lib/src/webkit_webview_controller.dart

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,7 @@ class WebKitWebViewController extends PlatformWebViewController {
235235
final JavaScriptAlertDialogRequest request =
236236
JavaScriptAlertDialogRequest(
237237
message: message,
238-
url: await frame.request.getUrl() ?? '',
238+
url: await frame.request?.getUrl() ?? '',
239239
);
240240
await callback.call(request);
241241
return;
@@ -253,7 +253,7 @@ class WebKitWebViewController extends PlatformWebViewController {
253253
final JavaScriptConfirmDialogRequest request =
254254
JavaScriptConfirmDialogRequest(
255255
message: message,
256-
url: await frame.request.getUrl() ?? '',
256+
url: await frame.request?.getUrl() ?? '',
257257
);
258258
final bool result = await callback.call(request);
259259
return result;
@@ -274,7 +274,7 @@ class WebKitWebViewController extends PlatformWebViewController {
274274
final JavaScriptTextInputDialogRequest request =
275275
JavaScriptTextInputDialogRequest(
276276
message: prompt,
277-
url: await frame.request.getUrl() ?? '',
277+
url: await frame.request?.getUrl() ?? '',
278278
defaultText: defaultText);
279279
final String result = await callback.call(request);
280280
return result;

packages/webview_flutter/webview_flutter_wkwebview/pigeons/web_kit.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -448,7 +448,7 @@ abstract class WKFrameInfo extends NSObject {
448448
late bool isMainFrame;
449449

450450
/// The frame’s current request.
451-
late URLRequest request;
451+
late URLRequest? request;
452452
}
453453

454454
/// Information about an error condition including a domain, a domain-specific

packages/webview_flutter/webview_flutter_wkwebview/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ name: webview_flutter_wkwebview
22
description: A Flutter plugin that provides a WebView widget based on Apple's WKWebView control.
33
repository: https://github.com/flutter/packages/tree/main/packages/webview_flutter/webview_flutter_wkwebview
44
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+webview%22
5-
version: 3.18.3
5+
version: 3.18.4
66

77
environment:
88
sdk: ^3.5.0

0 commit comments

Comments
 (0)