Obtenir tous les cookies de WKWebView

tout en obtenant des cookies de UIWebView semble simple en utilisant NSHTTPCookieStorage.sharedHTTPCookieStorage() , il semble WKWebView stocke les cookies ailleurs.

j'ai fait quelques recherches, et j'ai pu obtenir quelques cookies de l'attraper de NSHTTPURLResponse objet. ceci, cependant, ne contient pas tous les cookies utilisés par 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)
      }
    }
  }
}

étrangement, il y a aussi une classe WKWebsiteDataStore dans ios 9 qui est responsable de la gestion des cookies dans WKWebView , cependant, la classe ne contient pas de méthode publique pour récupérer les données des 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??
    }
  }
})

Est-il une solution pour obtenir les données du cookie?

42
demandé sur Lepidopteron 2015-10-15 22:09:39

10 réponses

enfin, httpCookieStore pour WKWebsiteDataStore atterri à iOS 11.

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

12
répondu Tualatrix Chou 2017-06-26 14:44:57
Les Cookies

utilisés (créés) par le WKWebView sont en fait correctement stockés dans le NSHTTPCookieStorage.sharedHTTPCookieStorage() .

le problème est que le WKWebView ne renvoie pas immédiatement les cookies. Je pense qu'il le fait selon son propre horaire. Par exemple quand un WKWebView est fermé ou peut-être périodiquement.

donc finalement ils finissent là-bas, mais quand est imprévisible.

vous pourriez être en mesure de forcez une synchronisation vers le NSHTTPCookieStorage partagé en fermant votre WKWebView . S'il vous plaît laissez-nous savoir si cela fonctionne.

Update : je viens de me rappeler que dans Firefox for iOS nous forçons le WKWebView à vider ses données internes, y compris les cookies, en remplaçant son WKProcessPool par un nouveau. Il n'y a pas D'API officielle, mais je suis sûr que c'est la solution la plus fiable pour l'instant.

51
répondu Stefan Arentz 2015-10-18 14:26:25

détails

Xcode 9.2, Swift 4

Solution

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

Utilisation

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

échantillon complet

  1. n'oubliez pas de ajouter le code de la solution ici
  2. ViewController a incorporez-vue-contrôleur
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

7
répondu Vasily Bodnarchuk 2018-09-12 18:13:47

je sais que c'est une question très ancienne, et nous avons une solution mais ne travaillons que sur iOS 11 et supérieur. Pour ceux qui ont affaire à iOS 10 et plus bas (comme moi), vous pouvez considérer cette méthode. Il fonctionne parfaitement pour moi:

  • Force de réinitialisation processPool:

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

-- > cela ne fonctionne que sur un appareil réel.

  • pour simulateur, vous devez ajouter:

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

suit la réponse de Stefan Arentz et Phenom.

6
répondu November Rain 2018-04-10 03:10:26

comme Stefan l'a mentionné, les cookies sont stockés dans NSHTTPCookieStorage.sharedHTTPCookieStorage()

cependant, d'après mes expériences, j'ai trouvé que les cookies de Session définis par le serveur ne sont pas visibles à NSHTTPCookieStorage.sharedHTTPCookieStorage() .

aussi longtemps que chaque WKWebView partage la même instance de WKProcessPool , ces cookies de Session seront transmis au serveur pour chaque requête. Si vous changez le pool de processus pour un WKWebView , vous supprimez essentiellement les cookies de session pour tout le futur demande.

1
répondu J.Thoo 2015-12-09 22:46:09

dans la pratique, j'ai trouvé dans la méthode de" decidePolicyForNavigationResponse", vous pouvez utiliser la façon suivante pour récupérer des cookies, mais la chose triste est qu'il n'est pas une liste complète/entière pour une session.

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

        let cookies = NSHTTPCookie.cookiesWithResponseHeaderFields(headFields, forURL: response.URL!)
1
répondu ikzjfr0 2017-01-12 12:56:59

dans NSHTTPCookie.cookiesWithResponseHeaderFields(headers, forURL: url) , que se passe-t-il si l'url où les cookies sont définis n'est pas une url de réponse de navigation (url qui provoque une navigation)? Je remarque que l'url de rappel où les cookies sont définis n'est jamais appelé dans 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!) 
}

ci-dessus délégué n'est jamais exécutée pour l'url de callback depuis le rappel lui-même n'a pas causé de navigation de la page.

cookies (avecréponse auxdéfis: pour:)

0
répondu Qin Zhengquan 2017-02-21 05:06:05

j'ai utilisé WKHTTPCookieStore dans Objective-C, cela a fonctionné pour moi d'obtenir à la fois les cookies persistants et de session, mais il ne fonctionne que dans 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çant le WKWebView à vider ses données internes en remplaçant son WKProcessPool comme décrit par la réponse de Stefan a fonctionné pour moi dans iOS 10 et 11 mais seulement pour les cookies persistants; il semble que les cookies de session soient supprimés, comme L'a décrit J. Thoo

0
répondu Jorge Duque 2018-07-31 17:56:03
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];
      }];
}
0
répondu Vivek 2018-08-20 11:33:53

Ce post a des informations utiles sur la gestion des cookies avec WKWebView. Selon cela, vous devriez être en mesure de définir et de récupérer des cookies en utilisant le standard Nslcache et NSHTTPCookie. Il se réfère également à l'utilisation de WKProccessPool selon le commentaire de Stephan.

-1
répondu Fuad Kamal 2015-11-30 18:55:34