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
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)