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?
7 Answers
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
- 670
- 1
- 11
- 25
- 20,519
- 3
- 38
- 55
-
2it's not working anymore now navigationAction.navigationType => .other for redirect – Sheshnath Jul 18 '18 at 11:02
-
-
-
ok @ShauketSheikh I will review it again, anyway check for the another answer maybe can help you, let me know – Reinier Melian Oct 08 '18 at 07:24
-
Thanks but i am facing very wierd issue for wkwebview ios 9 cookie are not updating for redirect uri – Muhammad Shauket Oct 08 '18 at 07:37
-
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 – Vijay Patidar Mar 12 '21 at 17:51
-
(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:
The
WKNavigationDelegatefunctionwebView(_:decidePolicyFor:decisionHandler:)is called for the original URL request.WKWebView'sURLproperty is set to the original URL.The
WKNavigationDelegatefunctionwebView(_:didStartProvisionalNavigation:)is called for the original URL request.WKWebView'sURLproperty is set to the original URL.The
WKWebView'sURLproperty is updated by WebKit to the redirection URL. (You'll only know about this if you are key-value observing the property.)The
WKNavigationDelegatefunctionwebView(_:decidePolicyFor:decisionHandler:)is called for the redirected URL request.WKWebView'sURLproperty is then redirection URL.The
WKNavigationDelegatefunctionwebView(_:didReceiveServerRedirectForProvisionalNavigation:)is called.WKWebView'sURLproperty 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.
- 4,399
- 37
- 44
-
Underrated answer. The `didReceiveServerRedirectForProvisionalNavigation` should be the way to go in this case. – Rexam Sep 23 '22 at 08:04
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()
}
- 151
- 1
- 4
-
This was the only solution that worked for me with my Vue 2 website where the page is not fully reloaded when pushing new paths to the Router – RyanG Feb 06 '23 at 16:09
Swift 5 Boom
Very easy way
func webView(_ webView: WKWebView, didReceiveServerRedirectForProvisionalNavigation navigation: WKNavigation!) {
if let url = webView.url?.absoluteString{
print("url = \(url)")
}
}
- 5,361
- 1
- 43
- 34
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
}
}
- 3,838
- 28
- 26
-
-
1This answer actually helped me a lot! My delegate method are not called either because the web view is not doing a full page reload, but its url did change. Also refer to @fmnavarretem answer's KVO syntax, it is in my opinion easier to understand. Also don't forget removing the observer on `deinit` or `viewWillDisappear` – Daniel Hu Sep 16 '22 at 21:24
Credits to Sven: https://forums.developer.apple.com/thread/117073
If you are facing a situation that your WebView doesn't open a PDF file or simply the url resolves to nothing, because the WebView's redirect URL doesn't come through you can use WKUIDelegate function webView(_:createWebViewWith:for:windowFeatures:) to capture the failed call and load the request again like:
extension WebViewWrapper: WKUIDelegate {
func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? {
if navigationAction.targetFrame == nil || navigationAction.targetFrame?.isMainFrame == false {
webView.load(navigationAction.request)
}
return nil
}
}
- 1,048
- 2
- 14
- 22
Use this WKNavigationDelegate method. I got redirect url from sourceFrame.request
public func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Swift.Void) {
let urlString = navigationAction.sourceFrame.request.url?.absoluteString ?? ""
print("\(urlString)")
decisionHandler(.allow)
}
- 77
- 10