Is there a way to see when an HTTPCookie is available to a WKWebView?

193 Views Asked by At

Disclaimer

I am aware that there are several issues related to this question and I have looked at all of them that I could, but they seem to be asking questions about how to sync the cookies in general. This is unlike those, in the sense that the cookies are properly transferred, there just seems to be a delay between when they are transferred vs. when they are available to the WKWebView

Situation

I have an application that uses a native login flow, then, post authentication, takes the user to a WKWebView for the content of the application. There seems to be an issue with setting cookies on a WKWebsiteDataStore's httpCookieStore (WKHTTPCookieStore).

The problem that I am experiencing is that, after I have set cookies on the httpCookieStore, there is a delay between the cookie being set (and the completion handler called) and when the cookie is actually available to the WKWebView.

Essentially, I call the set cookie method and, in its completion handler, I call load(_:) on the WKWebView. The web view loads as expected however, the first network calls made inside of the web view are missing the cookie that was just set. If I add a delay of say 500ms before calling load(_:) on the WKWebView the first network calls will have the cookie.

Code

In my view controller:


public override func viewDidLoad() {
    super.viewDidLoad()

    let config = WKWebViewConfiguration()
    config.websiteDataStore = WKWebsiteDataStore.default()
    config.processPool = self.webProcessPool // This is a WKProcessPool that is injected

    createWebView(configuration: config)

    // This method is defined in an extension below.
    webView.configuration.websiteDataStore.httpCookieStore.set(cookies: self.cookies) {
        // This completion is called and the web page is loaded as expected
        self.webView.load(URLRequest(url: self.navigationUrl))

        // The first requests made by the content loaded do not have the session cookie
        // which should have been present from the call to `set(cookies:)` however,
        // instead of calling load right away as we did above, if we add a delay here 
        // such as:
        //
        // self.cookieSettingDelaySubscribtion = Observable<Int>
        //        .interval(.milliseconds(500), scheduler: MainScheduler.instance)
        //        .take(1)
        //        .subscribe({ [unowned self] _ in
        //            self.webView.load(URLRequest(url: self.navigationUrl))
        //            self.cookieSettingDelaySubscribtion.dispose()
        //        })
        //
        // The cookie will be present on the first requests every time. 
    }
}


private func createWebView(configuration: WKWebViewConfiguration) {
    webView = WKWebView(frame: view.frame, configuration: configuration)

    // Setup code follows here 
}
extension WKHTTPCookieStore {
    /// Set multiple cookies, with a single completion handler.
    /// - parameters:
    ///   - cookies: The cookies to set.
    ///   - completion: A completion block to be called when all cookies have been set. The block
    ///                 will be called on the main queue.
    public func set(cookies: [HTTPCookie], completion: @escaping () -> Void) {
        let completionDispatchGroup = DispatchGroup()

        for cookie in cookies {
            completionDispatchGroup.enter()
            setCookie(cookie) {
                completionDispatchGroup.leave()
            }
        }

        completionDispatchGroup.notify(queue: .main, execute: completion)
    }
}

Question

I guess the question here is can anybody explain why there is a delay between the cookie being set and its completion handler being called, and when the cookie is actually available inside of the WkWebView and, is there a way (obviously outside of the set cookie completion since that is already happening) to know when the cookie becomes available inside of the WKWebView?

0

There are 0 best solutions below