在iOS的WKWebView中捕获重定向URL

49

在使用WKWebView时,如何捕获重定向URL,例如当网页在提交用户名和密码或其他数据时重定向到另一个页面。我需要捕获重定向的URL。在WKNavigationDelegate中是否有任何方法可以覆盖?


你好,昨天你的问题解决了吗? - Anbu.Karthik
使用 WKWebView 解决了该问题。 - Prabu Raj
好的,但是你没有告诉我。 - Anbu.Karthik
7个回答

47

(这个回答是关于如何在WKWebView中检测URL重定向的更一般问题,这是导致我访问此页面的搜索结果。)

简短回答

使用WKNavigationDelegatewebView(_:didReceiveServerRedirectForProvisionalNavigation:)函数,并检查WKWebViewURL属性。

更长的回答

你可以在几个地方检测服务器端重定向。

在iOS 10.3.3和iOS 11.0上,当加载一个被服务器重定向的URL时,我观察到的事件序列为:

  1. 对于原始URL请求,调用WKNavigationDelegate函数webView(_:decidePolicyFor:decisionHandler:)WKWebViewURL属性设置为原始URL。

  2. 对于原始URL请求,调用WKNavigationDelegate函数webView(_:didStartProvisionalNavigation:)WKWebViewURL属性设置为原始URL。

  3. WKWebViewURL属性由WebKit更新为重定向URL。(只有在键值观察该属性时才会知道这一点。)

  4. 对于重定向URL请求,调用WKNavigationDelegate函数webView(_:decidePolicyFor:decisionHandler:)WKWebViewURL属性然后是重定向URL。

  5. 调用WKNavigationDelegate函数webView(_:didReceiveServerRedirectForProvisionalNavigation:)WKWebViewURL属性是重定向URL。

(注意:在iOS 11.0模拟器上,我发现步骤3和4颠倒了,webView(_: decidePolicyFor: decisionHandler:)中的URL属性没有改变,实际上这似乎是个明智的排序方式,但我在设备上没有观察到这种情况。)
看起来 webView(_:didReceiveServerRedirectForProvisionalNavigation:) 是专门用于检测重定向的目的,因此可能是首选项,尽管在步骤3或4可能也可以推断出重定向,但前提是您可以确信没有其他导航更改的原因。

被低估的答案。在这种情况下,didReceiveServerRedirectForProvisionalNavigation 应该是正确的方法。 - Rexam

47

使用此 WKNavigationDelegate 方法

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)
    }

希望这可以帮助到你


2
现在它不再工作,navigationAction.navigationType => .other用于重定向。 - Sheshnath
@sheshnath 谢谢,我会检查并更新我的答案。 - Reinier Melian
谢谢,但我在WKWebView iOS 9上遇到了一个非常奇怪的问题,重定向URI的cookie没有更新。 - Muhammad Shauket
WKWebView在POST请求中不会自动设置Content-Type头为application/x-www-form-urlencoded。您可以手动将request.addValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")添加到标头中。 - Vijay Patidar
该方法对同一 URL 进行多次调用。 - Pramod Shukla
显示剩余2条评论

10

在尝试了所有解决方案之后,这个使用Swift 5和WKWebView的解决方案最终对我有用。此解决方案为Swift实现了KVO。

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()
}

这是我在使用Vue 2的网站中遇到页面在推送新路径到路由器时未能完全重新加载的唯一有效解决方案。 - RyanG
非常感谢你 :) 你救了我的一天 :) - undefined

7

Swift 5 火爆

非常简单的方法

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

5

对我来说,使用decidePolicyFor导航代理方法没有起作用。

它没有起作用是因为WKNavigationDelegate的方法

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

该方法只会在进行完整页面重新加载时调用。 为了能够捕获所有WKWebView的请求URL更改,需要在WKWebView的URL属性上放置一个键值观察器。

首先,在viewDidLoad中添加:

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

第二步,添加observeValue方法。

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
        }
    }

有趣,但我能得到一份关于这个的文档吗? - BollMose
1
这个答案对我帮助很大!我的委托方法没有被调用,因为网页视图没有进行完整的页面重新加载,但它的URL确实发生了变化。另外,请参考@fmnavarretem的答案中的KVO语法,我认为更容易理解。还要记得在deinitviewWillDisappear上移除观察者。 - Daniel Hu

2

感谢Sven:https://forums.developer.apple.com/thread/117073

如果您的WebView无法打开PDF文件或者仅仅是URL没有解析出来,因为WebView的重定向URL未传递,您可以使用WKUIDelegate函数webView(_:createWebViewWith:for:windowFeatures:)来捕获失败的请求并重新加载请求,例如:

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
使用这个WKNavigationDelegate方法。我从sourceFrame.request获取了重定向URL。
public func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Swift.Void) {
        let urlString = navigationAction.sourceFrame.request.url?.absoluteString ?? ""
        print("\(urlString)")
        decisionHandler(.allow)
 }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接