Getting all cookies from WKWebView

2020-01-23 15:23发布

while getting cookies from UIWebView seems straightforward by using NSHTTPCookieStorage.sharedHTTPCookieStorage(), it seems WKWebView stores the cookies somewhere else.

I did some research, and I was able to get some cookies from the grabbing it from NSHTTPURLResponse object. this, however, does not contain all the cookies used by 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)
      }
    }
  }
}

Strangely, there's also a class WKWebsiteDataStore in ios 9 that responsible for managing cookies in WKWebView, however, the class does not contain a public method to retrieve the cookies data:

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

Is there a workaround for getting the cookie data?

13条回答
▲ chillily
2楼-- · 2020-01-23 15:54

I used WKHTTPCookieStore in Objective-C, This worked for me to get both persistent and session cookies, but it only works 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);
        }
 }];

Forcing the WKWebView to flush its internal data by replacing its WKProcessPool as described by Stefan's answer worked for me in iOS 10 and 11 but only for persistent cookies; it seems like session cookies get removed, as J. Thoo described

查看更多
我欲成王,谁敢阻挡
3楼-- · 2020-01-23 15:47

I know this is a very old question, and we have a solution but work only on iOS 11 and upper. For those one who are dealing with iOS 10 and lower (like me), you may consider this method. It works perfectly to me:

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

--> this only work on real device.

  • For simulator, you should add:
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)
}

Follow to the answer of Stefan Arentz and Phenom.

查看更多
forever°为你锁心
4楼-- · 2020-01-23 15:48

Don't waste you time in extracting cookies from iOS 11 below device, there are very less chances of getting succeeded. Cookie extraction may get blocked due some security reasons.

Refer these logs:

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

Try this code which is build for below iOS 11 devices:

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

The above code will give you empty cookie array, as cookies extraction are being blocked due to some security reasons.

I would recommend you to try following which is meant for iOS 11 and above:

WKWebsiteDataStore.default().httpCookieStore.getAllCookies { (cookies) in
    for cookie in cookies {
        print(cookie)
    }
}
查看更多
孤傲高冷的网名
5楼-- · 2020-01-23 15:48

In NSHTTPCookie.cookiesWithResponseHeaderFields(headers, forURL: url), what happen if the url where the cookies are set is not a navigation response url (url that causes a navigation)? I notice the callback url where the cookies are set is never called in 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!) 
}

The above delegate is never executed for the callback url since the callback itself does not caused a page navigation.

cookies(withResponseHeaderFields:for:)

查看更多
萌系小妹纸
6楼-- · 2020-01-23 15:50

Cookies used (created) by the WKWebView are actually correctly stored in the NSHTTPCookieStorage.sharedHTTPCookieStorage().

The problem is that the WKWebView does not write back the cookies immediately. I think it does this on its own schedule. For example when a WKWebView is closed or maybe periodically.

So eventually they do end up in there, but when is unpredictable.

You may be able to force a 'sync' to the shared NSHTTPCookieStorage by closing your WKWebView. Please let us know if this works.

Update: I just remembered that in Firefox for iOS we force the WKWebView to flush its internal data, including cookies, by replacing its WKProcessPool with a new one. There is no official API, but I am pretty sure that is the most reliable workaround right now.

查看更多
我只想做你的唯一
7楼-- · 2020-01-23 15:51

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)
}
查看更多
登录 后发表回答