IT TIP

WKWebView에서 모든 쿠키 가져 오기

itqueen 2020. 12. 29. 08:14
반응형

WKWebView에서 모든 쿠키 가져 오기


UIWebView사용하여 쿠키를 가져 오는 것은 간단 NSHTTPCookieStorage.sharedHTTPCookieStorage()해 보이지만 WKWebView다른 곳에 쿠키를 저장하는 것 같습니다 .

나는 약간의 조사를했고, 나는 그것을 NSHTTPURLResponse물건 에서 잡아서 쿠키를 얻을 수 있었다 . 그러나 이것은에서 사용하는 모든 쿠키를 포함하지 않습니다 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 의 클래스도 WKWebView있지만 클래스에는 쿠키 데이터를 검색하는 공용 메서드가 포함되어 있지 않습니다.

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

쿠키 데이터를 가져 오는 해결 방법이 있습니까?


마지막으로 iOS 11 httpCookieStoreWKWebsiteDataStore탑재되었습니다.

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


에서 사용 (생성) 한 쿠키 WKWebView는 실제로 NSHTTPCookieStorage.sharedHTTPCookieStorage().

문제는 WKWebView쿠키를 즉시 다시 쓰지 않는다는 것입니다. 나는 그것이 자체 일정에 따라 이것을한다고 생각한다. 예를 들어 a WKWebView가 닫혀 있거나 주기적으로 닫힐 입니다.

그래서 결국 그들은 거기에 도착하지만 언제 예측할 수 없습니다.

NSHTTPCookieStorage를 닫아 공유 '동기화'를 강제 할 수 있습니다 WKWebView. 이것이 작동하는지 알려주십시오.

업데이트 : iOS 용 Firefox에서WKWebView 쿠키를 포함한 내부 데이터를 WKProcessPool것으로 대체하여 강제 로 플러시하도록했습니다 . 공식 API는 없지만 이것이 현재 가장 안정적인 해결 방법이라고 확신합니다.


세부

  • 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

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

여기에 이미지 설명 입력


나는 이것이 매우 오래된 질문이라는 것을 알고 있으며 해결책이 있지만 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)
}

Stefan Arentz와 Phenom의 대답을 따르십시오.


Objective-C에서 WKHTTPCookieStore를 사용했는데 영구 쿠키와 세션 쿠키를 모두 얻을 수 있었지만 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


As Stefan mentioned, cookies are stored in NSHTTPCookieStorage.sharedHTTPCookieStorage()

However, from my experiments, I found that Session cookies set by the server are not visible to NSHTTPCookieStorage.sharedHTTPCookieStorage().

As long as each WKWebView share the same instance of WKProcessPool, those Session cookies will be passed back to the server for each request. If you change the process pool for a WKWebView, you are essentially removing the session cookies for all future requests.


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

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

In practice, I found in the method of "decidePolicyForNavigationResponse", you can use following way to fetch cookies, but the sad thing is it's not a complete/whole list for a session.

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

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

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


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

For iOS 11, without any extensions:

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

This post has useful information on cookie handling with WKWebView. According to this you should be able to set and retrieve cookies using the standard NSURLCache and NSHTTPCookie. He also refers to using WKProccessPool as per Stephan's comment.

참조 URL : https://stackoverflow.com/questions/33156567/getting-all-cookies-from-wkwebview

반응형