Capture redirect url in wkwebview in ios

41,869

Solution 1

Use this WKNavigationDelegate method

public func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Swift.Void) {
        if(navigationAction.navigationType == .other) {
            if let redirectedUrl = navigationAction.request.url {
                //do what you need with url
                //self.delegate?.openURL(url: redirectedUrl)
            }
            decisionHandler(.cancel)
            return
        }
        decisionHandler(.allow)
    }

Hope this helps

Solution 2

(This answers the slightly more general question of how to detect a URL redirection in WKWebView, which is the search that lead me to this page.)

Short answer

Use WKNavigationDelegate's webView(_:didReceiveServerRedirectForProvisionalNavigation:) function and examine WKWebView's URL property.

Longer answer

There are a couple of places you could detect a server-side redirect.

On iOS 10.3.3 and iOS 11.0, the sequence of events I observe when loading a URL that gets redirected by the server is:

  1. The WKNavigationDelegate function webView(_:decidePolicyFor:decisionHandler:) is called for the original URL request. WKWebView's URL property is set to the original URL.

  2. The WKNavigationDelegate function webView(_:didStartProvisionalNavigation:) is called for the original URL request. WKWebView's URL property is set to the original URL.

  3. The WKWebView's URL property is updated by WebKit to the redirection URL. (You'll only know about this if you are key-value observing the property.)

  4. The WKNavigationDelegate function webView(_:decidePolicyFor:decisionHandler:) is called for the redirected URL request. WKWebView's URL property is then redirection URL.

  5. The WKNavigationDelegate function webView(_:didReceiveServerRedirectForProvisionalNavigation:) is called. WKWebView's URL property is the redirection URL.

(Note: On the iOS 11.0 simulator I have seen steps 3 and 4 reversed, with the URL property unchanged in webView(_:decidePolicyFor:decisionHandler:), which actually seems like a sensible ordering, but I haven't observed this on a device.)

It seems like the webView(_:didReceiveServerRedirectForProvisionalNavigation:) is built explicitly for the purpose of detecting redirects so is probably the preferred option, although the redirect could be possibly be inferred at steps 3 or 4 but only if you can be sure that there are no other causes of navigational change.

Solution 3

After trying all the solutions, finally this one works for me using Swift 5 and WKWebView.This solution implements KVO for Swift

var webView: WKWebView?
var webViewObserver: NSKeyValueObservation?

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    webView = WKWebView(frame: self.view.bounds)
    webViewObserver = webView?.observe(\.url, options: .new, changeHandler: {
        (currentWebView, _) in
        //      Here you go the new path
        currentWebView.url
    })
}

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    webViewObserver?.invalidate()
}

Solution 4

Swift 5 Boom

Very easy way

func webView(_ webView: WKWebView, didReceiveServerRedirectForProvisionalNavigation navigation: WKNavigation!) {
    if let url = webView.url?.absoluteString{
        print("url = \(url)")
    }
}

Solution 5

For me, using decidePolicyFor navigation delegate's method didn't work.

It didn't work because WKNavigationDelegate's method

func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void)

will only be called when there is a full-page reload. To be able to catch all WKWebView's request URL changes, a Key-Value observer will have to be placed on the WKWebView's URL property.

First, in viewDidLoad add:

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

Second, add observeValue method

override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
        if keyPath == #keyPath(WKWebView.url) {
            // Whenever URL changes, it can be accessed via WKWebView instance
            let url = webView.url
        }
    }
Share:
41,869
Prabu Raj
Author by

Prabu Raj

Updated on July 09, 2022

Comments

  • Prabu Raj
    Prabu Raj almost 2 years

    How do I capture the redirection url in when using WKWebView like if a webpage redirects to another page on submitting the username and password or some other data. I need to capture the redirected url. Is there any method in WKNavigationDelegate to override?

  • Sheshnath
    Sheshnath almost 6 years
    it's not working anymore now navigationAction.navigationType => .other for redirect
  • Reinier Melian
    Reinier Melian almost 6 years
    @sheshnath thanks I will review and update my answer
  • Reinier Melian
    Reinier Melian over 5 years
    @ShauketSheikh 16/08/2018
  • Reinier Melian
    Reinier Melian over 5 years
    ok @ShauketSheikh I will review it again, anyway check for the another answer maybe can help you, let me know
  • Muhammad Shauket
    Muhammad Shauket over 5 years
    Thanks but i am facing very wierd issue for wkwebview ios 9 😔😔😔 cookie are not updating for redirect uri
  • BollMose
    BollMose over 3 years
    Interesting, but can I get a document about this?
  • Vijay Patidar
    Vijay Patidar about 3 years
    WKWebView doesn't automatically set the Content-Type header to application/x-www-formurlencoded for POST requests You can add request.addValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type"). to headers manually
  • Pramod Shukla
    Pramod Shukla about 2 years
    this method calling multiple time for same url