Während das Abrufen von Cookies UIWebView
durch die Verwendung unkompliziert NSHTTPCookieStorage.sharedHTTPCookieStorage()
erscheint, WKWebView
werden die Cookies anscheinend an einem anderen Ort gespeichert.
Ich habe einige Nachforschungen angestellt und konnte einige Kekse erhalten, indem ich sie vom NSHTTPURLResponse
Objekt genommen habe. Dies enthält jedoch nicht alle Cookies, die verwendet werden von 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)
}
}
}
}
Seltsamerweise gibt es WKWebsiteDataStore
in ios 9 auch eine Klasse , die für die Verwaltung von Cookies verantwortlich WKWebView
ist. Die Klasse enthält jedoch keine öffentliche Methode zum Abrufen der Cookie-Daten:
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??
}
}
})
Gibt es eine Problemumgehung zum Abrufen der Cookie-Daten?
Antworten:
Schließlich
httpCookieStore
fürWKWebsiteDataStore
in iOS 11 gelandet.https://developer.apple.com/documentation/webkit/wkwebsitedatastore?changes=latest_minor
quelle
Von der verwendeten (erstellten) Cookies
WKWebView
werden tatsächlich korrekt in der gespeichertNSHTTPCookieStorage.sharedHTTPCookieStorage()
.Das Problem ist, dass
WKWebView
die Cookies nicht sofort zurückgeschrieben werden. Ich denke, das macht es nach eigenem Zeitplan. Zum Beispiel, wenn aWKWebView
geschlossen ist oder in regelmäßigen Abständen.Also landen sie schließlich dort, aber wann ist unvorhersehbar.
Möglicherweise können Sie eine Synchronisierung mit der Freigabe erzwingen,
NSHTTPCookieStorage
indem Sie Ihre schließenWKWebView
. Bitte lassen Sie uns wissen, ob dies funktioniert.Update : Ich habe mich gerade daran erinnert, dass wir in Firefox für iOS die
WKWebView
internen Daten, einschließlich Cookies, erzwingen müssen , indem wir sie durchWKProcessPool
neue ersetzen . Es gibt keine offizielle API, aber ich bin mir ziemlich sicher, dass dies derzeit die zuverlässigste Problemumgehung ist.quelle
WKWebView
'? removeFromSuperview und setze es auf nil?self.webView.configuration.processPool = [[WKProcessPool alloc] init];
und es hat funktioniert, um die Cookies zu spülen, damit sie verfügbar sindNSHTTPCookieStorage.sharedHTTPCookieStorage()
, aber es funktioniert nur auf dem Gerät für mich, nicht auf dem Simulator.Einzelheiten
Lösung
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) } } }
Verwendung
// 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) }
Vollständige Probe
Info.plist
Fügen Sie Ihre Transportsicherheitseinstellung Info.plist hinzu
<key>NSAppTransportSecurity</key> <dict> <key>NSAllowsArbitraryLoads</key> <true/> </dict>
Code
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)) } }
quelle
Ich weiß, dass dies eine sehr alte Frage ist, und wir haben eine Lösung, arbeiten aber nur unter iOS 11 und höher. Für diejenigen, die mit iOS 10 und niedriger zu tun haben (wie ich), können Sie diese Methode in Betracht ziehen. Es funktioniert perfekt für mich:
extension WKWebView { func refreshCookies() { self.configuration.processPool = WKProcessPool() // TO DO: Save your cookies,... } }
-> Dies funktioniert nur auf realen Geräten.
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) }
Folgen Sie der Antwort von Stefan Arentz und Phenom.
quelle
refreshCookies()
angerufen? Ich denke, bevor wir es brauchen, um die Cookies abzurufen? Es funktioniert immer noch nicht für die Website, die ich verwende und die auf einem tatsächlichen Gerät mit iOS 13.1.2 getestet wurde. Liegt es an Sitzungs- / dauerhaften Cookies?self.configuration.websiteDataStore.httpCookieStore.getAllCookies { (cookies) in /* your own code */}
. Bisher nur auf dem Gerät getestet (iOS 13).Ich habe WKHTTPCookieStore in Objective-C verwendet. Dies hat bei mir funktioniert, um sowohl dauerhafte als auch Sitzungscookies zu erhalten, aber es funktioniert nur in 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); } }];
Das Erzwingen des Löschens der internen Daten durch WKWebView durch Ersetzen des WKProcessPool, wie in Stefans Antwort beschrieben, funktionierte für mich in iOS 10 und 11, jedoch nur für dauerhafte Cookies. Es scheint, als würden Sitzungscookies entfernt, wie J. Thoo beschrieben hat
quelle
Für iOS 11 ohne Erweiterungen:
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { self.webView.configuration.websiteDataStore.httpCookieStore.getAllCookies { cookies in for cookie in cookies { //... } } }
quelle
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]; }]; }
quelle
Swift 5
func webView(_ webView: WKWebView, decidePolicyFor navigationResponse: WKNavigationResponse, decisionHandler: @escaping (WKNavigationResponsePolicy) -> Void) { webView.configuration.websiteDataStore.httpCookieStore.getAllCookies { cookies in debugPrint(cookies.debugDescription) } decisionHandler(.allow) }
quelle
Wie bereits von Stefan erwähnt, werden Cookies in gespeichert
NSHTTPCookieStorage.sharedHTTPCookieStorage()
Bei meinen Experimenten stellte ich jedoch fest, dass vom Server gesetzte Sitzungscookies für nicht sichtbar sind
NSHTTPCookieStorage.sharedHTTPCookieStorage()
.Solange jeder
WKWebView
dieselbe Instanz von gemeinsamWKProcessPool
nutzt, werden diese Sitzungscookies für jede Anforderung an den Server zurückgegeben. Wenn Sie den Prozesspool für a ändernWKWebView
, entfernen Sie im Wesentlichen die Sitzungscookies für alle zukünftigen Anforderungen.quelle
Verschwenden Sie keine Zeit mit dem Extrahieren von Cookies
iOS 11 below device
, da die Erfolgsaussichten sehr gering sind. Das Extrahieren von Cookies kann aus Sicherheitsgründen blockiert werden.Verweisen Sie auf diese Protokolle:
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
Probieren Sie diesen Code aus, der für Geräte unter iOS 11 erstellt wurde:
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) }
Mit dem obigen Code erhalten Sie ein leeres Cookie-Array, da die Extraktion von Cookies aus Sicherheitsgründen blockiert wird.
Ich würde Ihnen empfehlen, Folgendes zu versuchen, das für iOS 11 und höher gedacht ist:
WKWebsiteDataStore.default().httpCookieStore.getAllCookies { (cookies) in for cookie in cookies { print(cookie) } }
quelle
In der Praxis habe ich in der Methode "entscheidendPolicyForNavigationResponse" festgestellt, dass Sie Cookies auf folgende Weise abrufen können. Das Traurige ist jedoch, dass es sich nicht um eine vollständige Liste für eine Sitzung handelt.
let response = navigationResponse.response as! NSHTTPURLResponse let headFields = response.allHeaderFields as! [String:String] let cookies = NSHTTPCookie.cookiesWithResponseHeaderFields(headFields, forURL: response.URL!)
quelle
In
NSHTTPCookie.cookiesWithResponseHeaderFields(headers, forURL: url)
, was passiert , wenn die URL , wo die Cookies gesetzt werden ist keine Navigation Antwort url (url , die eine Navigation verursacht)? Ich stelle fest, dass die Rückruf-URL, unter der die Cookies gesetzt werden, in entscheidendPolicyFor Navigationsantwort nie aufgerufen wird.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!) }
Der obige Delegat wird niemals für die Rückruf-URL ausgeführt, da der Rückruf selbst keine Seitennavigation verursacht.
Cookies (withResponseHeaderFields: für :)
quelle
Dieser Beitrag enthält nützliche Informationen zum Umgang mit Cookies mit WKWebView. Demnach sollten Sie in der Lage sein, Cookies mit dem Standard-NSURLCache und NSHTTPCookie zu setzen und abzurufen. Er bezieht sich auch auf die Verwendung von WKProccessPool gemäß Stephans Kommentar.
quelle