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.
Methods
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.
Solution
Option 1
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")
Option 2
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)