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?
10 réponses
enfin, httpCookieStore
pour WKWebsiteDataStore
atterri à iOS 11.
https://developer.apple.com/documentation/webkit/wkwebsitedatastore?changes=latest_minor
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.
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
- n'oubliez pas de ajouter le code de la solution ici
- 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))
}
}
}
}
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.
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.
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!)
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.
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 +
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
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];
}];
}
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.