ios - Obtendo todos os cookies do WKWebView




swift uiwebview (9)

Detalhes

  • Xcode 9.2, Swift 4
  • Xcode 10.2 (10E125), Swift 5

Solução

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

Amostra completa

Info.plist

adicione sua configuração de segurança de transporte Info.plist

 <key>NSAppTransportSecurity</key>
 <dict>
    <key>NSAllowsArbitraryLoads</key>
    <true/>
 </dict>

Código

  1. Não esqueça de adicionar o código da solução aqui
  2. ViewController incorpora controlador de visão
import UIKit
import WebKit

class ViewController: UIViewController {

    private lazy var url = URL(string: "https://google.com")!
    private weak var webView: WKWebView?

    func initWebView(configuration: WKWebViewConfiguration) {
        if webView != nil { return }
        let webView = WKWebView(frame: UIScreen.main.bounds, configuration: configuration)
        webView.navigationDelegate = self
        webView.uiDelegate = self
        view.addSubview(webView)
        self.webView = webView
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        if webView == nil { initWebView(configuration: WKWebViewConfiguration()) }
        webView?.load(url: url)
    }
}

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? {
        // push new screen to the navigation controller when need to open url in another "tab"
        if let url = navigationAction.request.url, navigationAction.targetFrame == nil {
            let viewController = ViewController()
            viewController.initWebView(configuration: configuration)
            viewController.url = url
            DispatchQueue.main.async { [weak self] in
                self?.navigationController?.pushViewController(viewController, animated: true)
            }
            return viewController.webView
        }
        return nil
    }
}

extension WKWebView {

    func load(urlString: String) {
        if let url = URL(string: urlString) { load(url: url) }
    }

    func load(url: URL) { load(URLRequest(url: url)) }
}

Enquanto os cookies do UIWebView parecem simples, usando o NSHTTPCookieStorage.sharedHTTPCookieStorage() , parece que o WKWebView armazena os cookies em outro lugar.

Eu fiz algumas pesquisas, e consegui pegar alguns cookies do objeto NSHTTPURLResponse . isso, no entanto, não contém todos os cookies usados ​​pelo 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)
      }
    }
  }
}

Estranhamente, há também uma classe WKWebsiteDataStore no ios 9 responsável por gerenciar cookies no WKWebView , no entanto, a classe não contém um método público para recuperar os dados dos 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??
    }
  }
})

Existe uma solução alternativa para obter os dados do cookie?


Como Stefan mencionou, os cookies são armazenados em NSHTTPCookieStorage.sharedHTTPCookieStorage()

No entanto, em meus experimentos, descobri que os cookies da sessão definidos pelo servidor não são visíveis para NSHTTPCookieStorage.sharedHTTPCookieStorage() .

Desde que cada WKWebView compartilhe a mesma instância de WKProcessPool , esses cookies de sessão serão passados ​​de volta para o servidor para cada solicitação. Se você alterar o pool de processos de um WKWebView , estará essencialmente removendo os cookies de sessão para todas as solicitações futuras.


Eu sei que esta é uma questão muito antiga, e nós temos uma solução, mas funcionam apenas no iOS 11 e superior. Para aqueles que estão lidando com o iOS 10 e menor (como eu), você pode considerar este método. Isso funciona perfeitamente para mim:

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

-> isso só funciona em dispositivo real.

  • Para simulador, você deve adicionar:
func webView(_ webView: WKWebView, decidePolicyFor navigationResponse: WKNavigationResponse, decisionHandler: @escaping (WKNavigationResponsePolicy) -> Void) {
    if let response = navigationResponse.response as? HTTPURLResponse,
       let allHttpHeaders = response.allHeaderFields as? [String: String],
       let responseUrl = response.url {
        let cookies = HTTPCookie.cookies(withResponseHeaderFields: allHttpHeaders, for: responseUrl)

        for cookie in cookies {
            HTTPCookieStorage.shared.setCookie(cookie)
        }
    }

    decisionHandler(.allow)
}

Siga para a resposta de Stefan Arentz e Phenom.


Eu usei WKHTTPCookieStore em Objective-C, isso funcionou para mim para obter cookies persistentes e de sessão, mas só funciona no 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);
        }
 }];

Forçando o WKWebView a liberar seus dados internos, substituindo seu WKProcessPool, como descrito pela resposta de Stefan, funcionou para mim no iOS 10 e 11, mas apenas para cookies persistentes; parece que cookies de sessão são removidos, como J. Thoo descreveu


Não perca tempo na extração de cookies do iOS 11 below device , há muito menos chances de obter sucesso. A extração de cookies pode ser bloqueada por alguns motivos de segurança.

Consulte estes logs:

let response = navigationResponse.response as! NSHTTPURLResponse
        let headFields = response.allHeaderFields as! [String:String]

        let cookies = NSHTTPCookie.cookiesWithResponseHeaderFields(headFields, forURL: response.URL!)

Experimente este código que é criado para dispositivos abaixo do iOS 11:

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

O código acima fornecerá um array de cookies vazio, já que a extração de cookies está sendo bloqueada devido a alguns motivos de segurança.

Eu recomendo que você tente seguir o que é para o iOS 11 e acima:

2019-02-07 00:05:45.548880+0530 MyApp[2278:280725] [BoringSSL] nw_protocol_boringssl_get_output_frames(1301) [C8.1:2][0x10fd776f0] get output frames failed, state 8196

2019-02-07 00:05:45.550915+0530 MyApp[2278:280725] TIC Read Status [8:0x0]: 1:57

Na prática, eu encontrei no método de "decidePolicyForNavigationResponse", você pode usar o seguinte caminho para buscar cookies, mas o triste é que não é uma lista completa / inteira para uma sessão.

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

        let cookies = HTTPCookie.cookies(withResponseHeaderFields: headFields, for: response.url!)
        for cookie in cookies {
            print("name: \(cookie.name) value: \(cookie.value)")
        }
        decisionHandler(.allow)
    }

Para o iOS 11 , sem extensões:

 func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { self.webView.configuration.websiteDataStore.httpCookieStore.getAllCookies { cookies in for cookie in cookies { //... } } } 

Esta postagem contém informações úteis sobre o tratamento de cookies com o WKWebView. De acordo com isso, você deve ser capaz de definir e recuperar cookies usando o padrão NSURLCache e NSHTTPCookie. Ele também se refere ao uso de WKProccessPool conforme o comentário de Stephan.


if (@available(iOS 11.0, *)) {
  [webView.configuration.websiteDataStore.httpCookieStore
      getAllCookies:^(NSArray<NSHTTPCookie *> *_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];
      }];
}






wkwebview