Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WKWebView setting Cookie not possible (iOS 11+)

I am desperately trying to add a custom cookie to a WKWebView instance (without using Javascript or similar workarounds).

From iOS 11 and upwards, Apple provides an API to do this: The WKWebViews WKWebsiteDataStore has a property httpCookieStore.

Here is my (example) code:

import UIKit
import WebKit

class ViewController: UIViewController {

    var webView: WKWebView!

    override func viewDidLoad() {
        webView = WKWebView()
        view.addSubview(webView)
        super.viewDidLoad()
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

        let cookie = HTTPCookie(properties: [
            HTTPCookiePropertyKey.domain : "google.com",
            HTTPCookiePropertyKey.path : "/",
            HTTPCookiePropertyKey.secure : true,
            HTTPCookiePropertyKey.name : "someCookieKey",
            HTTPCookiePropertyKey.value : "someCookieValue"])!

        let cookieStore = webView.configuration.websiteDataStore.httpCookieStore
        cookieStore.setCookie(cookie) {
            DispatchQueue.main.async {
                self.webView.load(URLRequest(url: URL(string: "https://google.com")!))
            }
        }
    }

    override func viewWillLayoutSubviews() {
        super.viewWillLayoutSubviews()

        webView.frame = view.bounds
    }
}

After this, if I use webView.configuration.websiteDataStore.httpCookieStore.getAllCookies(completionHandler:) I see that my cookie is in the list of cookies.

However, when inspecting the webview using Safari's developer tools (using a iOS Simulator of course) the cookie does not show up.

I also tried to inspect the traffic using a HTTP proxy (Charles in my case) to see if the cookie in included in my HTTP requests. It is not.

What am I doing wrong here? How can I add a cookie to WKWebView (on iOS versions 11 and up)?

like image 458
naglerrr Avatar asked Jun 21 '18 17:06

naglerrr


People also ask

Is WKWebView deprecated?

Since then, we've recommended that you adopt WKWebView instead of UIWebView and WebView — both of which were formally deprecated. New apps containing these frameworks are no longer accepted by the App Store.

What is iOS WKWebView?

A WKWebView object is a platform-native view that you use to incorporate web content seamlessly into your app's UI. A web view supports a full web-browsing experience, and presents HTML, CSS, and JavaScript content alongside your app's native views.

Does WKWebView share cookies with Safari?

WKWebView is an in-app browser that displays web content. It doesn't share cookies or web site data with other WKWebView instances, or with the Safari browser.

Does WKWebView store cookies?

The code above has no effect with the new web view since each WKWebView instance has its own cookie storage represented by WKHTTPCookieStore class.


2 Answers

A bit late but I want to share a solution that worked for me, I hope it helps someone facing the same issue on iOS 12 as well.

Here is the simplified workflow I used:

  1. Instantiate a WKWebsiteDataStore object
  2. Set the custom cookie to its httpCookieStore
  3. Wait for the cookie to be set
  4. Instantiate the WKWebView
  5. Load the request

To do that I have created an extension of WKWebViewConfiguration:

extension WKWebViewConfiguration {

static func includeCookie(cookie:HTTPCookie, preferences:WKPreferences, completion: @escaping (WKWebViewConfiguration?) -> Void) {
     let config = WKWebViewConfiguration()
     config.preferences = preferences

     let dataStore = WKWebsiteDataStore.nonPersistent()

     DispatchQueue.main.async {
        let waitGroup = DispatchGroup()

        waitGroup.enter()
        dataStore.httpCookieStore.setCookie(cookie) {
            waitGroup.leave()
        }

        waitGroup.notify(queue: DispatchQueue.main) {
            config.websiteDataStore = dataStore
            completion(config)
        }
    }
}

And for my example I have used it as follows:

override func viewDidLoad() {
  self.AddWebView()
}

private func addWebView(){

    let preferences = WKPreferences()
    preferences.javaScriptEnabled = true
    preferences.javaScriptCanOpenWindowsAutomatically = true

    let cookie = HTTPCookie(properties: [
        .domain: COOKIE_DOMAIN,
        .path: "/",
        .name: COOKIE_NAME,
        .value: myCookieValue,
        .secure: "TRUE",
        .expires: NSDate(timeIntervalSinceNow: 3600)
        ])

     //Makes sure the cookie is set before instantiating the webview and initiating the request
     if let myCookie = cookie {
        WKWebViewConfiguration.includeCookie(cookie: myCookie, preferences: preferences, completion: {
           [weak self] config in
              if let `self` = self {
                 if let configuration = config {
                    self.webView = WKWebView(frame: CGRect(x: 0, y: 0, width: self.view.frame.size.width , height: self.view.frame.height), configuration: configuration)

                    self.view.addSubview(self.webView)
                    self.webView.load(self.customRequest)
                 }
              }
     }
}
like image 91
SwissMark Avatar answered Oct 03 '22 22:10

SwissMark


Any request to google.com redirects to www.google.com.

You would need to add www. to the domain field of the cookie. If the domain or the path doesn't match the request, the cookie won't be sent.

You can add the cookies explicitly.

let url = URL(string: "https://www.google.com")!
var request = URLRequest(url: url)
if let cookies = HTTPCookieStorage.shared.cookies(for: url) {
    request.allHTTPHeaderFields = HTTPCookie.requestHeaderFields(with: cookies)
}
self.webView.load(request)
like image 20
Onato Avatar answered Oct 03 '22 20:10

Onato