从WKWebView获取所有的cookies

虽然通过使用NSHTTPCookieStorage.sharedHTTPCookieStorage()UIWebView获取cookie似乎很简单,但似乎WKWebView将cookie存储在别的地方。

我做了一些研究,并从NSHTTPURLResponse对象中获取了一些cookie。 但是,这并不包含WKWebView使用的所有Cookie:

 func webView(webView: WKWebView, decidePolicyForNavigationResponse navigationResponse: WKNavigationResponse, decisionHandler: (WKNavigationResponsePolicy) -> Void) { if let httpResponse = navigationResponse.response as? NSHTTPURLResponse { if let headers = httpResponse.allHeaderFields as? [String: String], url = httpResponse.URL { let cookies = NSHTTPCookie.cookiesWithResponseHeaderFields(headers, forURL: url) for cookie in cookies { logDebug(cookie.description) logDebug("found cookie " + cookie.name + " " + cookie.value) } } } } 

奇怪的是,在iOS 9中还有一个类WKWebsiteDataStore负责pipe理WKWebView cookie,但是该类不包含公共方法来检索cookie数据:

 let storage = WKWebsiteDataStore.defaultDataStore() storage.fetchDataRecordsOfTypes([WKWebsiteDataTypeCookies], completionHandler: { (records) -> Void in for record in records { logDebug("cookie record is " + record.debugDescription) for dataType in record.dataTypes { logDebug("data type is " + dataType.debugDescription) // get cookie data?? } } 

有没有解决方法来获取cookie数据?

最后, httpCookieStoreWKWebsiteDataStore在iOS 11中登陆。

https://developer.apple.com/documentation/webkit/wkwebsitedatastore?changes=latest_minor

WKWebView使用(创build)的WKWebView实际上正确存储在NSHTTPCookieStorage.sharedHTTPCookieStorage()

问题是WKWebView不会立即写回cookie。 我认为这是按照自己的时间表。 例如,当一个WKWebView被closures或者可能是周期性的。

所以最终他们最终在那里,但是什么时候是不可预测的。

您可以通过closures您的WKWebView来强制“共享” WKWebView 。 请让我们知道这是否工作。

更新 :我只记得,在iOS版的Firefox中,我们强制WKWebView通过replace它的WKWebView来刷新其内部数据,包括cookie。 没有官方的API,但我很确定这是目前最可靠的解决方法。

正如Stefan所说,cookie存储在NSHTTPCookieStorage.sharedHTTPCookieStorage()

但是,从我的实验中,我发现服务器设置的会话cookie对于NSHTTPCookieStorage.sharedHTTPCookieStorage()是不可见的。

只要每个WKWebView共享同一个WKWebView实例, WKProcessPool这些会话Cookie将会被传回给服务器以用于每个请求。 如果您更改WKWebView的进程池,则实际上将删除所有未来请求的会话Cookie。

在实践中,我发现在“decidePolicyForNavigationResponse”的方法中,可以使用下面的方法来获取cookie,但可悲的是它不是一个完整/整个会话列表。

 let response = navigationResponse.response as! NSHTTPURLResponse let headFields = response.allHeaderFields as! [String:String] let cookies = NSHTTPCookie.cookiesWithResponseHeaderFields(headFields, forURL: response.URL!) 

这篇文章有关于使用WKWebView进行cookie处理的有用信息。 据此,你应该可以使用标准的NSURLCache和NSHTTPCookie来设置和检索cookie。 他还提到按照Stephan的评论使用WKProccessPool。

NSHTTPCookie.cookiesWithResponseHeaderFields(headers, forURL: url) ,如果Cookie设置的url不是导航响应url(导致导航的url)会发生什么? 我注意到cookies设置的callbackurl在决定政策导航响应中从来不会被调用。

 func webView(_ webView: WKWebView, decidePolicyFor navigationResponse: WKNavigationResponse, decisionHandler: @escaping (WKNavigationResponsePolicy) -> Void) { let response = navigationResponse.response as! HTTPURLResponse let cookies = HTTPCookie.cookies(withResponseHeaderFields: response.allHeaderFields as! [String : String], for: response.url!) } 

上面的委托永远不会执行callbackurl,因为callback本身不会导致页面导航。

cookies(withResponseHeaderFields:为:)

细节

xCode 9.2,Swift 4

 extension WKWebView { private var httpCookieStore: WKHTTPCookieStore { return WKWebsiteDataStore.default().httpCookieStore } func getCookies(for domain: String? = nil, completion: @escaping ([String : Any])->()) { var cookieDict = [String : AnyObject]() httpCookieStore.getAllCookies { (cookies) in for cookie in cookies { if let domain = domain { if cookie.domain.contains(domain) { cookieDict[cookie.name] = cookie.properties as AnyObject? } } else { cookieDict[cookie.name] = cookie.properties as AnyObject? } } completion(cookieDict) } } } 

用法

 // get cookies for domain webView.getCookies(for: url.host) { data in print("=========================================") print("\(url.absoluteString)") print(data) } // get all cookies webView.getCookies() { data in print("=========================================") print("\(url.absoluteString)") print(data) } 

完整的样品

  1. 不要忘记在这里添加解决scheme代码
  2. ViewControllerembedded了视图控制器
 import UIKit import WebKit class ViewController: UIViewController { var urlString = "http://google.com" var webView: WKWebView! fileprivate var webViewIsInited = false override func viewDidLoad() { super.viewDidLoad() } override func viewWillLayoutSubviews() { if !webViewIsInited { webViewIsInited = true if webView == nil { webView = WKWebView(frame: UIScreen.main.bounds, configuration: WKWebViewConfiguration()) } view.addSubview(webView) webView.navigationDelegate = self webView.uiDelegate = self webView.loadUrl(string: urlString) } } } extension ViewController: WKNavigationDelegate { func webView(_ webView: WKWebView, decidePolicyFor navigationResponse: WKNavigationResponse, decisionHandler: @escaping (WKNavigationResponsePolicy) -> Void) { decisionHandler(.allow) } func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { if let url = webView.url { webView.getCookies(for: url.host) { data in print("=========================================") print("\(url.absoluteString)") print(data) } } } } extension ViewController: WKUIDelegate { func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? { if navigationAction.targetFrame == nil { let vc = ViewController() vc.urlString = navigationAction.request.url?.absoluteString ?? "http://google.com" vc.view.frame = UIScreen.main.bounds vc.webView = WKWebView(frame: UIScreen.main.bounds, configuration: configuration) navigationController?.pushViewController(vc, animated: false) return vc.webView } return nil } } extension WKWebView { func loadUrl(string: String) { if let url = URL(string: string) { if self.url?.host == url.host { self.reload() } else { load(URLRequest(url: url)) } } } } 

在这里输入图像说明