In case if your webview loads a part of body(or whole html body) additionally, then you won't have desired results by evaluating your javascript inside of method:
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!)
Reason for this is because "didFinish" method is called once navigation is done inside of webview, but not strictly after loading whole content inside of webView which could be in states:
- state: empty body
- state: some loading
- state: javascript framework did his job and inserted app-body inside
- state: body has content
"didFinish" is called in state 1.
You can wait for some time with DispatchQueue.main.asyncAfter and then do the .evaluateJavascript but it will make webView makes changes in front of user(ugly per my opinion...)
My proposal would be this extension:
extension WKWebView {
// it re-execute javascript in cases when body is attached additionally on the html by some inner javascript framework
// it tries around 50 times maximum in time range of 10 sec
// if body is not loaded in 10 secs, this won't work
func rexecuteJavascript(tryouts: Int = 0, script: String) {
self.evaluateJavaScript(script, completionHandler: { (result: Any?, error: Error?) in
if let _ = error, tryouts < 50 {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) {
return self.rexecuteJavascript(tryouts: tryouts + 1, script: script)
}
}
})
}
}
It works perfectly for me because body of webview gets populated in around 2-3 secs after "didFinish", and I use this to execute my javascript on fully loaded body:
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
let removeFooterScript = "document.getElementsByClassName('global-footer')[0].style.display='none';"
webView.rexecuteJavascript(script: removeFooterScript)
}
Cheers!