16
votes

How do you detect when a link was clicked in a WKWebView? I'm looking for the equivalent of this in a UIWebView.

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
    if(navigationType == UIWebViewNavigationTypeLinkClicked)
    {

    }
    return YES;
}

I tried this in the WKNavigationDelegate but I only ever get WKNavigationTypeOther for all requests even when clicking on links.

- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
{
    if(navigationAction.navigationType == WKNavigationTypeLinkActivated)
    {

    }
    decisionHandler(WKNavigationActionPolicyAllow);
}
1
What about webView(_:didCommitNavigation:)? - Gasim
Just checked, and I get WKNavigationTypeLinkActivated after click on a link. Checked under iOS 9.1 and iOS 8.2. - Borys Verebskyi
I'm working with iOS 9.2. I did some more testing and it seems it's links around images not working. The documentation just says A link with an href attribute was activated by the user. for WKNavigationTypeLinkActivated. - Berry Blue
Yep, when I click on an image inside of <a> tag, I get WKNavigationTypeOther. Looks like another one WKWebView bug to me. - Borys Verebskyi
Ok, thank you for verifying! I will log a bug. @Gasim, thanks for your comment too. That approach does work instead. - Berry Blue

1 Answers

17
votes

What you can do in a WkWebView is the following:

override func viewDidLoad() {
    super.viewDidLoad()

     let webView = WKWebView()
     self.view.addSubview(webView) // you need to also setup constraints here - I left out for clarity
     // Make sure you set the delegate, so you get the callback
     self.webView.navigationDelegate = self
}

 // WKWebViewNavigationDelegate
 func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
     guard let url = navigationAction.request.url, let scheme = url.scheme, scheme.contains("http") else {
            // This is not HTTP link - can be a local file or a mailto
            decisionHandler(.cancel)
            return
        }
     // This is a HTTP link
     open(url: url)
     decisionHandler(.allow)
}

In this delegate method, you get the URL request that the WKWebView is trying to open. There you can check the attributes of the URLRequest and respond accordingly.

You can even write an extension for URLRequest that handles that logic, so you can reuse it.

extension URLRequest {
    var isHttpLink: Bool {
        return self.url?.scheme?.contains("http") ?? false
    }
}

Then you can change the long condition in the delegate method to:

 // WKWebViewNavigationDelegate
 func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
   guard navigationAction.request.isHttpLink else {
        decisionHandler(.allow)
        return
    }
   // ... handle url