Reputation: 877
I have a WKWebView app running on iOS8 on iPad (standard iPad UserAgent : "Mozilla/5.0 (iPad; CPU OS 8_1_1 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) Version/8.0 Mobile/12B436 Safari/600.1.4"). I have tried all delegates and listeners I can think of to try and detect when a page has finished loading, every time. Here is the problem:
Open your WKWebView and go to Google. The following are called:
_decidePolicyForNavigationAction
_didStartProvisionalNavigation
_ didFinishNavigation
Type “YouTube” into Google: ONLY _decidePolicyForNavigationAction is called. No didStartProvisionalNavigation or didFinishNavigation
Click on YouTube within Google. The following are called:
_didStartProvisionalNavigation
_decidePolicyForNavigationAction
_ didFinishNavigation
From now on, within YouTube nothing is called. Click on a YouTube video and no didStartProvisionalNavigation or didFinishNavigation. Also, webview.loading observer is no longer called. Even decidePolicyForNavigationAction is only called every now and then. HOWEVER… The webView.backForwardList.currentItem is updated after every click, so this must be detecting when the page has finished loading somehow?
This behavior happens on a lot of other sites too (Vimeo for example). I know this type of site is not updating the main frame every time, but is this lack of a capability to detect when loading has started/finished a ‘limitation’ of WKWebView in its current state?
What I want to achieve is: Is there another way to detect when navigation has COMPLETED, EVERY TIME within Java mobile websites like YouTube/Vimeo:
Thanks for any help.
Upvotes: 21
Views: 16112
Reputation: 4356
If anyone is looking for solution how to use the observer, here is the solution:
webView.addObserver(self, forKeyPath: "title", options: .new, context: nil);
webView.addObserver(self, forKeyPath: "loading", options: .new, context: nil);
webView.addObserver(self, forKeyPath: "estimatedProgress", options: .new, context: nil);
Then use observeValue
function and write a switch-case or if-else to find the keyPath
.
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if keyPath == "title" {
print(change ?? "No title")
if change != nil, let currentTitle = change?[.newKey] as? String {
titleLabel.text = currentTitle
}
} else if keyPath == "loading" {
print("Loading")
reloadButton.setImage(#imageLiteral(resourceName: "cancel.png"), for: .normal)
} else if keyPath == "estimatedProgress" {
print(wkWebView.estimatedProgress);
progressView.progress = Float(wkWebView.estimatedProgress)
}
}
Here I have created a demo project to explore more about WebKit WebView.
Upvotes: 1
Reputation: 1633
I'm not sure what exactly you want to do when page have loaded, but hopefully observing these properties can help you:
webView.addObserver(self, forKeyPath: "estimatedProgress", options: .New, context: nil)
webView.addObserver(self, forKeyPath: "loading", options: .New, context: nil)
webView.addObserver(self, forKeyPath: "title", options: .New, context: nil)
webView.addObserver(self, forKeyPath: "canGoBack", options: .New, context: nil)
webView.addObserver(self, forKeyPath: "canGoForward", options: .New, context: nil)
Upvotes: 13