6
votes

Goal: inject third part cookies into WKWebView.

Before iOS 12 I was able to fix the problem through this snippet (see https://medium.com/@flexaddicted/how-to-set-wkwebview-cookie-accept-policy-d8a2d3b77420):

func webView(_ webView: WKWebView, decidePolicyFor navigationResponse: WKNavigationResponse, decisionHandler: @escaping (WKNavigationResponsePolicy) -> Void) {
  guard let response = navigationResponse.response as? HTTPURLResponse,
    let url = navigationResponse.response.url else {
    decisionHandler(.cancel)
    return
  }

  if let headerFields = response.allHeaderFields as? [String: String] {
    let cookies = HTTPCookie.cookies(withResponseHeaderFields: headerFields, for: url)
    cookies.forEach { cookie in
      webView.configuration.websiteDataStore.httpCookieStore.setCookie(cookie)
    }
  }

  decisionHandler(.allow)
}

Starting from iOS 12 cookies are not available in WKWebView's response.

https://bugs.webkit.org/show_bug.cgi?id=188691

Do you know any workaround to fix this?

1
Have you ever managed to solve this issue?timbru31
@timbru31 nope, sorryLorenzo B

1 Answers

0
votes

I think I found a solution, but it's a bit "hacky".

Create a method that returns URL :

  1. Create a DispatchSemaphore to send synchronous request
  2. Execute request in URLSession
  3. At the end of DataTask, retrieve response?.url

Before loading content in WKWebView, set cookies in WKWebView from URLSession.

And it works like a charm.

func getAuthenticatedURL(from url: URL) -> URL? {
    let session = URLSession.shared
    let semaphore = DispatchSemaphore(value:0)

    var result: URL? = nil

    session.dataTask(with: url) { _, response, _ in
        result = response?.url
        semaphore.signal()
    }.resume()

    semaphore.wait()

    return result
}

let conf = WKWebViewConfiguration()

let ctrl = WKUserContentController()

conf.userContentController = ctrl

let wkDataStore = WKWebsiteDataStore.nonPersistent()

wkDataStore.removeData(
    ofTypes: WKWebsiteDataStore.allWebsiteDataTypes(),     
    modifiedSince: .distantPast) { }

HTTPCookieStorage.shared
                .cookies?
                .forEach { wkDataStore.httpCookieStore.setCookie($0) }

conf.websiteDataStore = wkDataStore

wkWebView = WKWebView(frame: .zero, configuration: conf)

// ...

// Get URL from getAuthenticatedURL and load in wkWebView