从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数据?
最后, httpCookieStore
的WKWebsiteDataStore
在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) }
完整的样品
- 不要忘记在这里添加解决scheme代码
- 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)) } } } }