Is there any way to get the Javascript errors from the Webview? I mean the following errors and possible warnings?
I run JS code with the following extension
```
extension WKWebView {
func evaluateJavaScriptWithReturn(_ javaScriptString: String) -> String? {
var finished = false
var jsValue: String?
evaluateJavaScript(javaScriptString) { (result, error) in
if error == nil {
if result != nil {
jsValue = result as? String
}
} else {
jsValue = nil
}
finished = true
}
while !finished {
RunLoop.current.run(mode: .defaultRunLoopMode, before: Date.distantFuture)
}
return jsValue
}
}
```
But error
is not what i'm looking for!
Is there any way to get in my app, the above errors?
Thanks a lot!
How to run JavaScript on a WKWebView with evaluateJavaScript() Using evaluateJavaScript() you can run any JavaScript in a WKWebView and read the result in Swift. This can be any JavaScript you want, which effectively means you can dig right into a page and pull out any kind of information you want.
Debugging with WKWebViewOpen Safari and press ⌘+, to open Preference, under the Advanced tab, check “Show Develop menu in menu bar”. Not until we have the project build can we use the Safari debugger. The debugger is under Develop → Your simulator or device.
Unlike UIWebView, which does not support server authentication challenges, WKWebView does. In practical terms, this means that when using WKWebView, you can enter site credentials for password-protected websites.
The WKWebView is a modern API applying all the modern web security mechanisms, it's still maintained by Apple and gets updates. The good thing about WKWebView is that it does out-of-process rendering, so if the attackers find a memory corruption vulnerability in it, your application's process is still isolated.
To handle errors, we are going to add some JavaScript to the HTML we load into our page that will notify our native code about the error.
First, you need to setup your web view with a script message handler:
let controller = WKUserContentController()
controller.add(self, name: "error")
let configuration = WKWebViewConfiguration()
configuration.userContentController = controller
let webView = WKWebView(frame: .zero, configuration: configuration)
I locally create the full HTML document and inject the following JavaScript:
window.onerror = (msg, url, line, column, error) => {
const message = {
message: msg,
url: url,
line: line,
column: column,
error: JSON.stringify(error)
}
if (window.webkit) {
window.webkit.messageHandlers.error.postMessage(message);
} else {
console.log("Error:", message);
}
};
(I have the check and log since I sometime run the generated JavaScript in a browser.) You could also use the WKUserContentController
to add a WKUserScript
if you want to inject it into HTML you don’t fully control.
Next when you load a string into your web view, be sure to use localhost
as the base URL. If you don’t do this, all of your errors will be "Script error."
.
webView.loadHTMLString(html, baseURL: URL(string: "http://localhost/")!)
Now define your WKScriptMessageHandler
:
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
switch message.name {
case "error":
// You should actually handle the error :)
let error = (message.body as? [String: Any])?["message"] as? String ?? "unknown"
assertionFailure("JavaScript error: \(error)")
default:
assertionFailure("Received invalid message: \(message.name)")
}
}
You can add other cases to the switch statement for other messages you add to the WKUserContentController
.
Try the following way.
First, inject JS code to catch the error in html content:
window.onerror = function(error) {
alert(error); // Fire when errors occur. Just a test, not always do this.
};
Second, display the error in WKWebView delegate method:
func webView(_ webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping () -> Void) {
let alertController = UIAlertController(title: "alert", message: message, preferredStyle: UIAlertControllerStyle.alert)
alertController.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.cancel, handler: nil))
self.present(alertController, animated: true, completion: nil)
print("An error from web view: \(message)")
}
Remember to set delegate:
webView.uiDelegate = self
If you want to avoid the alerts, the alternative way is using decidePolicyForNavigationAction
method to receive the JS's callback which is like window.open("error://message","_self")
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With