从WKWebView获取所有cookie


70

使用来获取cookieUIWebView似乎很简单NSHTTPCookieStorage.sharedHTTPCookieStorage(),似乎WKWebView将cookie存储在其他位置。

我做了一些研究,然后从NSHTTPURLResponse对象中获取了一些Cookie 。但是,其中不包含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)
      }
    }
  }
}

奇怪的是WKWebsiteDataStore,ios 9中还有一个类负责在中管理cookie WKWebView,但是,该类不包含检索cookie数据的公共方法:

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

是否有解决方法来获取Cookie数据?


值得注意的是,WebKit团队似乎正在以一种正确的方式来访问WKWebView的cookie存储:bugs.webkit.org/show_bug.cgi?id=140191
robotspacer

@aporat您是否找到了任何解决方案,我几个月来一直在努力,但尚未得到任何解决方案:(
ZAFAR007'Apr 1'17


@aporat您没有提到获取cookie数据:)
Shauket Sheikh '18

Answers:



74

所使用(创建)的CookieWKWebView实际上已正确存储在中NSHTTPCookieStorage.sharedHTTPCookieStorage()

问题在于WKWebView不会立即写回cookie。我认为它按自己的时间表进行。例如,当aWKWebView关闭或定期关闭时。

因此,最终它们确实会在那里出现,但是何时是不可预测的。

您可以NSHTTPCookieStorage通过关闭来强制“同步”到共享WKWebView。请让我们知道是否可行。

更新:我只记得在iOS的Firefox中,我们WKWebView通过用WKProcessPool新的替换它来强制刷新其内部数据(包括cookie)。目前尚无官方API,但我可以肯定,这是目前最可靠的解决方法。


8
谢谢。我会检查一下。您是否具有执行该WKProcessPool开关的功能的参考?我只是用一个新的池替换池吗?
aporat

任何人都可以使用此答案中描述的解决方法吗?
tapmonkey

“关闭WKWebView”是什么意思?removeFromSuperview并将其设置为nil?
卢卡斯·维尔茨堡

我需要WKWebView Cookie的帮助。
西瓦

7
对于那些对此感到困惑的人,我确实做到了: self.webView.configuration.processPool = [[WKProcessPool alloc] init]; 它可以刷新cookie,因此它们可以在中使用NSHTTPCookieStorage.sharedHTTPCookieStorage(),但是它仅对我适用,而不对模拟器有效。
飞鸿(Phenom)

20

细节

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

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

用法

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

完整样本

信息清单

添加您的Info.plist传输安全设置

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

  1. 不要忘记在此处添加解决方案代码
  2. ViewController已嵌入视图控制器
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)) }
}

在此处输入图片说明


我可以获得完整的项目吗?
沙希德·加富尔

@ShahidGhafoor当然,dropbox.com
s /

14

我知道这是一个非常老的问题,我们有一个解决方案,但只能在iOS 11及更高版本上使用。对于那些正在处理iOS 10及更低版本(如我)的用户,您可以考虑使用此方法。它对我来说很完美:

  • 强制重置过程池:
extension WKWebView {
    func refreshCookies() {
        self.configuration.processPool = WKProcessPool()
        // TO DO: Save your cookies,...
    }
}

->仅适用于真实设备。

  • 对于模拟器,您应该添加:
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)
}

跟随斯蒂芬·阿伦茨和飞鸿的答案。


您是否忘记了如何实际复制Cookie?
强尼

什么时候refreshCookies()打?我猜想我们需要它来检索Cookie吗?在运行iOS 13.1.2的实际设备上测试过,我所使用的网站仍然无法正常工作。是因为会话/持久性Cookie吗?
Cyber​​Mew

我回来投票支持我添加的cookie self.configuration.websiteDataStore.httpCookieStore.getAllCookies { (cookies) in /* your own code */}。到目前为止仅在设备上测试过(iOS 13)。
强尼

总是我得到空的“ cookies”数组。请帮助我
Yogendra Patel

4

我在Objective-C中使用了WKHTTPCookieStore,这对我来说可以获得持久性Cookie和会话Cookie,但仅在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);
        }
 }];

按照Stefan的回答所述,通过替换WKWebPool强制WKWebView刷新其内部数据在iOS 10和11中对我有效,但仅对持久性cookie有效;正如J. Thoo所述,似乎会话cookie被删除了


嗨,jorge,您针对iOS 13.0及更高版本的解决方案是什么?
埃尔多安

4

对于iOS 11,没有任何扩展名:

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

3
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];
      }];
}

谢谢您的回答对我有帮助,但它适用于iOS 11.0或更高版本。我想对iOS 10或更低版本执行相同的执行。请帮我。意味着我需要把所有cookies在iOS的10
Yogendra特尔

3

迅捷5

func webView(_ webView: WKWebView, decidePolicyFor navigationResponse: WKNavigationResponse, decisionHandler: @escaping (WKNavigationResponsePolicy) -> Void) {
    webView.configuration.websiteDataStore.httpCookieStore.getAllCookies { cookies in
        debugPrint(cookies.debugDescription)
    }

    decisionHandler(.allow)
}

2

正如Stefan所说,Cookie存储在 NSHTTPCookieStorage.sharedHTTPCookieStorage()

但是,从我的实验中,我发现服务器看不到服务器设置的会话cookie NSHTTPCookieStorage.sharedHTTPCookieStorage()

只要每个WKWebView共享相同的实例WKProcessPool,这些会话cookie就会针对每个请求传递回服务器。如果您更改的进程池WKWebView,则实际上是在删除所有将来请求的会话Cookie。


是的,可以说cookie存储在NSHTTPCookieStorage.sharedHTTPCookieStorage()中。但是,问题是:如果用户已经登录UIWebView,则不会自动登录另一个WKWebView副签证。所以我的信念是:即使它们共享相同的cookie,其背后的原理也有很大不同
ikzjfr0

1

不要浪费时间从中提取Cookie iOS 11 below device,获得成功的机会要少得多。由于某些安全原因,cookie提取可能会被阻止。

请参考以下日志:

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

尝试为以下iOS 11设备构建的以下代码:

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

上面的代码将为您提供空的Cookie数组,因为出于某些安全原因,Cookie提取被阻止。

我建议您尝试以下方法,该方法适用于iOS 11及更高版本:

WKWebsiteDataStore.default().httpCookieStore.getAllCookies { (cookies) in
    for cookie in cookies {
        print(cookie)
    }
}

0

在实践中,我在“ decidePolicyForNavigationResponse”方法中发现,可以使用以下方式来获取Cookie,但可悲的是,它不是会话的完整列表。

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

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

0

在中NSHTTPCookie.cookiesWithResponseHeaderFields(headers, forURL: url),如果设置Cookie的网址不是导航响应网址(导致导航的网址)会发生什么?我注意到在从来没有在DecisionPolicyFor navigationResponse中调用设置cookie的回调URL。

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

由于回调本身不会导致页面导航,所以永远不会对回调URL执行以上委托。

Cookies(withResponseHeaderFields:for :)


-1

这篇文章提供了有关使用WKWebView处理cookie的有用信息。据此,您应该能够使用标准的NSURLCache和NSHTTPCookie设置和检索cookie。他还提到了根据Stephan的评论使用WKProccessPool。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.