Getting all cookies from WKWebView
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.
Details
- Xcode 9.2, Swift 4
- Xcode 10.2 (10E125), Swift 5
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) } }}
Usage
// get cookies for domainwebView.getCookies(for: url.host) { data in print("=========================================") print("\(url.absoluteString)") print(data)}// get all cookieswebView.getCookies() { data in print("=========================================") print("\(url.absoluteString)") print(data)}
Full sample
Info.plist
add in your Info.plist transport security setting
<key>NSAppTransportSecurity</key> <dict> <key>NSAllowsArbitraryLoads</key> <true/> </dict>
Code
- Do not forget to add the solution code here
- ViewController has embed view controller
import UIKitimport WebKitclass 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)) }}