21

Is there a function for the WKWebView class that allows you to detect whenever the URL of that WebView has changed?

The didCommit and didStartProvisionalNavigation functions don't always seem to fire when working with certain elements within the WebView.

EDIT: Attempted adding a Notification observer. Here's what I have thus far:

extension Notification.Name {
    static let checkURL = Notification.Name("checkURL")
}

NotificationCenter.default.post(name: .checkURL, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(getter: webView.url), name: .checkURL, object: webView.url)
JDev
  • 5,168
  • 6
  • 40
  • 61

3 Answers3

33

Swift Version

// Add observer
webView.addObserver(self, forKeyPath: "URL", options: .new, context: nil)

// Observe value
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
    if let key = change?[NSKeyValueChangeKey.newKey] {
        print("observeValue \(key)") // url value
    }
}
Atalyk
  • 495
  • 1
  • 5
  • 11
15

What do you mean they don't always seem to fire? What kind of elements? They have to in order for the WkWebView to work.

Your first indication that the URL is trying to change is in: decidePolicyForNavigationAction

- (void) webView: (WKWebView *) webView decidePolicyForNavigationAction: (WKNavigationAction *) navigationAction decisionHandler: (void (^)(WKNavigationActionPolicy)) decisionHandler {
    NSLog(@"%s", __PRETTY_FUNCTION__);
    decisionHandler(WKNavigationActionPolicyAllow); //Always allow
    NSURL *u1 = webView.URL;
    NSURL *u2 = navigationAction.request.URL; //If changing URLs this one will be different
}

By the time you get to: didStartProvisionalNavigation It has changed.

- (void) webView: (WKWebView *) webView didStartProvisionalNavigation: (WKNavigation *) navigation {
    NSLog(@"%s", __PRETTY_FUNCTION__);
    NSURL *u1 = webView.URL;  //By this time it's changed
}

All you'd have to do is implement these delegate methods (in Swift) and do what you want when you see it change.

hawkeyecoder
  • 571
  • 4
  • 10
  • I apologize for the late reply, but this worked perfectly! Thank you very much! – JDev Nov 09 '17 at 17:28
  • what is "__PRETTY_FUNCTION__"? I'm not familiar with it. Also, Matt - do you have the swift code that worked perfectly? I'm having trouble converting this to swift 4 – jbrown94305 Mar 09 '18 at 16:09
  • @jbrown94305 It's a special identifier originally from C++ used to retrieve, and in this case print, the name of the function that encloses it. Pretty cool feature for logging purposes. Here's an [explanation](https://stackoverflow.com/questions/4384765/whats-the-difference-between-pretty-function-function-func) with a little more detail. – Ian Rahman Jun 19 '18 at 18:16
  • decidePoliceForNavigationAction is skipped depending on context – aehlke Jul 31 '23 at 19:11
4

You may add an observer:

[webView_ addObserver:self forKeyPath:@"URL" options:NSKeyValueObservingOptionNew context:NULL];

and the corresponding method that gets called when the URL changes:

-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context

John
  • 8,468
  • 5
  • 36
  • 61
  • Would you happen to know how to implement using Swift? I created a Notification and added it to my original post. The Notification syntax in Swift is fairly different and I have exhausted all of the possible attempts that I am capable of. I don't know where to go from here. – JDev Jan 02 '17 at 21:57