How To Open Webview Links In Safari

You have a web view in your application but would like any links clicked to open in Safari. Here’s the solution.

For WKWebView, first ensure your view controller conforms to WKNavigationDelegate

class MyViewController: UIViewController, WKNavigationDelegate {
  // TODO: code here
}

I like to put it in an extension to keep things neat:

extension MyViewController: WKNavigationDelegate {
  // TODO: code here
}

Next you need to implement the decidePolicyFor navigationAction function:

extension MyViewController: WKNavigationDelegate {
    func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
        if navigationAction.navigationType == .linkActivated  {
            if let url = navigationAction.request.url,
                UIApplication.shared.canOpenURL(url) {
                    UIApplication.shared.open(url)
                    decisionHandler(.cancel)
            } else {
                // Open in web view
                decisionHandler(.allow)
            }
        } else {
            // other navigation type, such as reload, back or forward buttons
            decisionHandler(.allow)
        }
    }
}

Lastly, you’ll need to set the navigation delegate in viewDidLoad() or in the storyboard:

 override func viewDidLoad() {
    super.viewDidLoad()
    webView.navigationDelegate = self
}

For UIWebView (which is a deprecated by the way), use the below code:

First, you must ensure that your view controller conforms to UIWebViewDelegate.

class MyViewController: UIViewController, UIWebViewDelegate {
  // TODO: code here
}

You could also do this in an extension to keep things neat:

extension MyViewController: UIWebViewDelegate {
  // TODO: code here
}

Then you need to implement the webViewShouldStartLoadingWithRequest:navigationType: function:

extension MyViewController: UIWebViewDelegate {
    func webView(_ webView: UIWebView, shouldStartLoadWith request: URLRequest, navigationType: UIWebView.NavigationType) -> Bool {
        switch navigationType {
        case .linkClicked:
            guard let url = request.url else { return true }
            if #available(iOS 10.0, *) {
                UIApplication.shared.open(url, options: [:], completionHandler: nil)
            } else {
                UIApplication.shared.openURL(url)
            }
            return false
        default:
            // TODO: handle other navigation types such reload, back or forward...
            return true
        }
    }
}

Lastly, you’ll need to set the delegate of your webview in your viewDidLoad() or in your storyboard/XIB.

override func viewDidLoad() {
    super.viewDidLoad()
    webview.delegate = self
}

If you only want to open certain domains in Safari, perform a check on the URL string in the delegate method.

WKWebView

For example, if we’re using a WKWebView and we only want to open google.com links in Safari, we would add this check:

if let host = url.host, host.hasPrefix("www.google.com") {
  // TODO: redirect to browser
}

Full code example for WKWebView:

extension MyViewController: WKNavigationDelegate {
    func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
        if navigationAction.navigationType == .linkActivated  {
            if let url = navigationAction.request.url,
                let host = url.host, host.hasPrefix("www.google.com") &&
                UIApplication.shared.canOpenURL(url) {
                    UIApplication.shared.open(url)
                    decisionHandler(.cancel)
            } else {
                // Open in web view
                decisionHandler(.allow)
            }
        } else {
            // other navigation type, such as reload, back or forward buttons
            decisionHandler(.allow)
        }
    }
}

UIWebView

We can perform a URL host check for the UIWebView:

if let host = url.host, host.hasPrefix("www.google.com") {
   // TODO: Open url in Safari
}

Full code example:

extension MyViewController: UIWebViewDelegate {
    func webView(_ webView: UIWebView, shouldStartLoadWith request: URLRequest, navigationType: UIWebView.NavigationType) -> Bool {
        switch navigationType {
        case .linkClicked:
            guard let url = request.url, let host = url.host, host.hasPrefix("www.google.com") else { return true }
            if #available(iOS 10.0, *) {
                UIApplication.shared.open(url, options: [:], completionHandler: nil)
            } else {
                UIApplication.shared.openURL(url)
            }
            return false
        default:
            // TODO: handle other navigation types such reload, back or forward...
            return true
        }
    }
}
If you liked this post and want to learn more, check out The Complete iOS Developer Bootcamp. Speed up your learning curve - hundreds of students have already joined. Thanks for reading!

Eddy Chung

I teach iOS development on ZeroToAppStore.com.

Similar Posts