Reputation: 6380
WKWebView
crashes while trying to evaluate JavaScript on Xcode 14.1, using Swift, tested on iOS but same behaviour should be on macOS.
I made a vastly simplified example to try to find a solution, and it keeps crashing:
let webView = WKWebView()
Task {
try? await webView.evaluateJavaScript("console.log('hello world')")
}
:0: Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value
Upvotes: 11
Views: 4596
Reputation: 634
just delete this block in InAppWebView
public override func evaluateJavaScript(_ javaScriptString: String, completionHandler: ((Any?, Error?) -> Void)? = nil) {
if let applePayAPIEnabled = settings?.applePayAPIEnabled, applePayAPIEnabled {
if let completionHandler = completionHandler {
completionHandler(nil, nil)
}
return
}
super.evaluateJavaScript(javaScriptString, completionHandler: completionHandler)
}
Upvotes: 0
Reputation: 61
another option could be something like:
@MainActor
func evaluateJavaScript(string javaScriptString: String) async throws {
try await withCheckedThrowingContinuation { (continuation: CheckedContinuation<Void, Error>) in
evaluateJavaScript(javaScriptString) { _, error in
if let error = error {
continuation.resume(throwing: error)
} else {
continuation.resume()
}
}
}
}
Upvotes: 6
Reputation: 6380
Seems that part of the problem is method overload, as of Xcode 14.1 there are several methods named evaluateJavaScript
as part of WKWebView
.
Due to optional parameters they seem to have the same signature, and the compiler is having a hard time understanding which one we mean.
open func evaluateJavaScript(_ javaScriptString: String, completionHandler: ((Any?, Error?) -> Void)? = nil)
open func evaluateJavaScript(_ javaScriptString: String) async throws -> Any
@MainActor public func evaluateJavaScript(_ javaScript: String, in frame: WKFrameInfo? = nil, in contentWorld: WKContentWorld, completionHandler: ((Result<Any, Error>) -> Void)? = nil)
@MainActor public func evaluateJavaScript(_ javaScript: String, in frame: WKFrameInfo? = nil, contentWorld: WKContentWorld) async throws -> Any?
After testing different scenarios it seems that when using async/await
version of these methods WKWebView
expects JavaScript to return with a value (something other than Void
), if there is no value returning from the JavaScript that you evaluate you will have a crash.
Always make sure JavaScript returns a value.
Crashing:
try? await webView.evaluateJavaScript("console.log('hello world')") // fatal error
Not crashing:
try? await webView.evaluateJavaScript("console.log('hello world'); 0")
When not possible to return a value explicitly use the signature with a completion handler (even if you pass nil as the handler).
webView.evaluateJavaScript("console.log('hello world')", completionHandler: nil)
Upvotes: 23