Obtener todas las cookies de WKWebView

mientras que obtener cookies de UIWebView parece sencillo al usar NSHTTPCookieStorage.sharedHTTPCookieStorage() , parece que WKWebView almacena las cookies en otro lugar.

Investigué un poco, y pude obtener algunas cookies del objeto NSHTTPURLResponse . esto, sin embargo, no contiene todas las cookies utilizadas por WKWebView :

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

Curiosamente, también hay una clase WKWebsiteDataStore en ios 9 que se encarga de administrar las cookies en WKWebView ; sin embargo, la clase no contiene un método público para recuperar los datos de las cookies:

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

¿Hay alguna solución para obtener los datos de las cookies?

Finalmente, httpCookieStore para WKWebsiteDataStore aterrizó en iOS 11.

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

Las cookies utilizadas (creadas) por WKWebView se almacenan correctamente en NSHTTPCookieStorage.sharedHTTPCookieStorage() .

El problema es que WKWebView no devuelve las cookies de inmediato. Creo que hace esto en su propio horario. Por ejemplo, cuando un WKWebView está cerrado o quizás periódicamente.

Entonces eventualmente terminan ahí, pero cuando es impredecible.

Puede forzar una “sincronización” con el NSHTTPCookieStorage compartido cerrando su WKWebView . Por favor, háganos saber si esto funciona.

Actualización : Acabo de recordar que en Firefox para iOS WKWebView al WKWebView a eliminar sus datos internos, incluidas las cookies, al reemplazar su WKProcessPool por una nueva. No hay API oficial, pero estoy bastante seguro de que es la solución más confiable en este momento.

Detalles

xCode 9.2, Swift 4

Solución

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

Uso

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

Muestra completa

  1. No olvides agregar el código de la solución aquí
  2. ViewController ha incorporado control de vista
 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)) } } } } 

enter image description here

Sé que esta es una pregunta muy antigua, y tenemos una solución, pero solo funciona en iOS 11 y superior. Para aquellos que están lidiando con iOS 10 y menor (como yo), puede considerar este método. Funciona perfectamente para mí:

  • Force reset processPool:
 extension WKWebView { func refreshCookies() { self.configuration.processPool = WKProcessPool() // TO DO: Save your cookies,... } } 

Como Stefan mencionó, las cookies se almacenan en NSHTTPCookieStorage.sharedHTTPCookieStorage()

Sin embargo, de mis experimentos, descubrí que las cookies de sesión establecidas por el servidor no son visibles para NSHTTPCookieStorage.sharedHTTPCookieStorage() .

Siempre que cada WKWebView comparta la misma instancia de WKProcessPool , esas cookies de sesión se transmitirán al servidor para cada solicitud. Si cambia el grupo de procesos para un WKWebView , esencialmente está eliminando las cookies de sesión para todas las solicitudes futuras.

En la práctica, encontré en el método de “decidePolicyForNavigationResponse”, puede usar la siguiente forma para obtener cookies, pero lo triste es que no es una lista completa / completa para una sesión.

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

En NSHTTPCookie.cookiesWithResponseHeaderFields(headers, forURL: url) , ¿qué ocurre si la URL donde se configuran las cookies no es una url de respuesta de navegación (url que provoca una navegación)? Noto que la url de callback donde se establecen las cookies nunca se llama en decidePolicyFor navigationResponse.

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

El delegado anterior nunca se ejecuta para la url de callback ya que la callback en sí no causa una navegación de página.

cookies (withResponseHeaderFields: para 🙂

Utilicé WKHTTPCookieStore en Objective-C. Esto me ayudó a obtener cookies persistentes y de sesión, pero solo funciona en iOS 11+

https://developer.apple.com/documentation/webkit/wkhttpcookiestore?changes=latest_minor&language=objc

  if (@available(iOS 11.0, *)) { WKHTTPCookieStore *cookieStore = _webView.configuration.websiteDataStore.httpCookieStore; [cookieStore getAllCookies:^(NSArray* cookies) { NSHTTPCookie *cookie; for(cookie in cookies){ NSLog(@"cookie: %@", cookie); } }]; 

Obligar a WKWebView a eliminar sus datos internos al reemplazar su WKProcessPool como lo describe la respuesta de Stefan funcionó para mí en iOS 10 y 11, pero solo para las cookies persistentes; parece que se eliminan las cookies de sesión, como describió J. Thoo

 if (@available(iOS 11.0, *)) { [webView.configuration.websiteDataStore.httpCookieStore getAllCookies:^(NSArray *_Nonnull cookies) { NSURLRequest *request = [[NSURLRequest alloc] initWithURL:self.URL]; //your URL NSURLSession *session = [NSURLSession sharedSession]; NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData *responseData, NSURLResponse *response, NSError *error) { //Do Something }]; [task resume]; [session.configuration.HTTPCookieStorage storeCookies:cookies forTask:task]; }]; } 

Esta publicación contiene información útil sobre el manejo de cookies con WKWebView. De acuerdo con esto, debería poder establecer y recuperar cookies utilizando el estándar NSURLCache y NSHTTPCookie. También se refiere a usar WKProccessPool según el comentario de Stephan.