20 Replies
      Latest reply on Oct 17, 2019 2:42 AM by nortan.nathan
      rd.apple Level 1 Level 1 (0 points)

        I created a method to set cookies from HTTPCookieStorage into WKHTTPCookieStorage, as it seems this api is full async so i created an async method that sets the cookies in wkHTTPCookieStorage.

         

        func copyCookiesToWKStore(completion: @escaping () -> Void) {
                if let httpCookies: [HTTPCookie] = self.httpCookieStorage.cookies {
                    print("updating wkCookies with httpCookies: \(httpCookies)")
                    func copyCookiesAsync(index: Int, cookieHandler: SDCookiesHandler?) {
                        if let cookieHandler = cookieHandler, index < httpCookies.count {
                            let cookie = httpCookies[index]
                            cookieHandler.wkCookieStore.setCookie(cookie, completionHandler: {
                                print("set cookie in Cookie Storage: \(cookie)")
                                DispatchQueue.main.async {
                                    copyCookiesAsync(index: index + 1, cookieHandler: cookieHandler)
                                }
                            })
                        }
                        else {
                            completion()
                        }
                    }
                    weak var cookieHandler = self
                    copyCookiesAsync(index: 0, cookieHandler: cookieHandler)
                } else {
                    completion()
                }
            }
        

         

         

        and the load the request in the wkwebview:

         

        wkCookiesHandler.copyCookiesToWKStore { [weak self] in
            if let weakSelf = self {
               DispatchQueue.main.async {
                  weakSelf.webView.load(cookiesRequest)
               }
            }
        

         

         

        However when webview calls the decidePolicyFor navigationAction method, the cookies in WKCookieStorage are not fully synced at this point.

        I have read in some posts that WKProcessPool has its own cycle to sync cookies, and that resetting it, causes cookies to sync with wkwebview, but i found that i am in existent webview flow, it causes weird artifacts with the webview.

        Has anyone started using WKCookieStorage api, and how can one keep cookies inserted in this api, visible by the WKWebview.

        • Re: Setting cookies with WKHTTPCookieStorage do not sync with wkwebview
          pkurzok Level 1 Level 1 (0 points)

          Hi,

           

          I have a similar problem. I used to sync HTTPCookieStorage with WKHTTPCookieStore with the following method.

          @available(iOS 11.0, *)
              func fillCookieStore(store: WKHTTPCookieStore, completionHandler: (() -> Void)? = nil) {
                 
                  DDLogDebug("HttpCookieStorage: \(String(describing: HTTPCookieStorage.shared.cookies))")
                 
                  if let cookies = HTTPCookieStorage.shared.cookies {
                     
                      let sem = DispatchGroup()
                      for cookie in cookies {
                          sem.enter()
                          store.setCookie(cookie, completionHandler: {
                              sem.leave()
                          })
                      }
                     
                      sem.notify(queue: .main) {
                          completionHandler?()
                      }
                  } else {
                      completionHandler?()
                  }
              }
          

           

          This used to work just fine until iOS 11.3 Beta. Since then my cookies are not available anymore. I have no clue what to do.

           

          Best regards

          Peter

            • Re: Setting cookies with WKHTTPCookieStorage do not sync with wkwebview
              rd.apple Level 1 Level 1 (0 points)

              Hi Peter,

               

              Does your code work well with iOS versions before 11.3, (11.3 is still in beta so you might have a solution). Do you insert your cookies before setting the configuration into webview, or does this work even if the configuration is set?

              Most of our cases scenarios require us to set the cookies to an existent webview and a share WKProcessPool.

               

               

              Regards

                • Re: Setting cookies with WKHTTPCookieStorage do not sync with wkwebview
                  pkurzok Level 1 Level 1 (0 points)

                  Hi,

                  it work's well for all version greater 11.0 and before 11.3. I insert the cookies AFTER setting the configuration to webview. Out of curiosity I tried to insert them before. But that doesnt work.

                   

                  Best regards

                  Peter

                    • Re: Setting cookies with WKHTTPCookieStorage do not sync with wkwebview
                      rd.apple Level 1 Level 1 (0 points)

                      This is rather strange, just out of curiosity how many webviews instances do you have running and also are your WKProcessPools shared or isolated.

                      I found that when i set the cookies before i call load(request) in the wkwebview, the cookies werent updated when decided decidePolicyFor navigationAction: WKNavigationAction is called.

                       

                      At this point the webview is part of the its superview, the configuration is set, and it is using a shared WKProcessPool, i found if i create at this point a new process pool the the cookies are inserted, but sometimes pages dont load correctly...

                       

                      When do you set the cookies, before or after adding it to subview?

                       

                      Apologies for picking your brain, just trying to understand the differences between ur approach and mine, when i finished adding my cookies to WKCookiestorage, if get all cookies i could see them there, but not when i called them at the decidePolicyFor navigationAction: WKNavigationAction method, which is rather strange.

                       

                      To me it seems its all related to the WKProcessPool and it update schedule, but maybe i am wrong.

                • Re: Setting cookies with WKHTTPCookieStorage do not sync with wkwebview
                  RicardoKoch Level 1 Level 1 (0 points)

                  We have apps in production with this problem since iOS 11.3 was released causing users to give us 1 stars ratings. Apple must find a solution to this problem ASAP. Our code is really not different than the others solutions I see here.

                  • Re: Setting cookies with WKHTTPCookieStorage do not sync with wkwebview
                    gkonchady Level 1 Level 1 (0 points)

                    Same problem for us. Our approach is very similar to the two posted here. Everything worked fine on every device prior to 11.3, but it fails on every device running 11.3 and above.

                      • Re: Setting cookies with WKHTTPCookieStorage do not sync with wkwebview
                        gkonchady Level 1 Level 1 (0 points)

                        Below are some code snippets from our implementation. Again, all of this worked fine prior to iOS 11.3. I tried adding an observer to the WKHTTPCookieStore associated with the WKWebView instance, but "cookiesDidChange" never seems to be hit.

                         

                           
                             // Create the WKWebView instance. Add a cookie store observer.
                            if #available(iOS 11, *){
                                wkWebView = WKWebView()
                                wkWebView!.scrollView.delegate = self
                                wkWebView!.configuration.websiteDataStore.httpCookieStore.add(OnShiftWKHTTPCookieStoreObserver())
                            }
                        
                        
                            // this is how we're adding cookies to our WKWebView instance.
                            public func writeCookies(cookies: [[HTTPCookiePropertyKey : Any]]) {
                                if #available(iOS 11, *) {
                                    let cookiesStore = wkWebView.configuration.websiteDataStore.httpCookieStore
                                    cookies.forEach { (cookie) in
                                        guard let cookie = HTTPCookie.init(properties: cookie) else {
                                            return
                                        }
                                        cookiesStore.setCookie(cookie, completionHandler: {
                                            print ("cookie added: \(cookie.name)")
                                        })
                                    }
                                }
                            }
                        
                        
                        // This is our WKHTTPCookieStoreObserver implementation. Note that "cookiesDidChange" isn't called
                        // even after several calls to setCookie above.
                        class OnShiftWKHTTPCookieStoreObserver: NSObject, WKHTTPCookieStoreObserver {
                            @available(iOS 11.0, *)
                            func cookiesDidChange(in cookieStore: WKHTTPCookieStore) {
                                cookieStore.getAllCookies({(cookies: [HTTPCookie]) in
                                    cookies.forEach({(cookie: HTTPCookie) in
                                        print("COOKIE name: \(cookie.name) domain: \(cookie.domain) value: \(cookie.value)")
                                    })
                                })
                            }
                        }
                        
                      • Re: Setting cookies with WKHTTPCookieStorage do not sync with wkwebview
                        LinhT_24 Level 1 Level 1 (0 points)

                        The problem with syncing cookies to WKWebView lies in WKProcessPool. To properly sync cookie,  you have to create an instance of WKProcessPool and set it to the WKWebViewConfiguration that is to be used to initialize the WkWebview itself:

                         

                            private lazy var mainWebView: WKWebView = {
                                let webConfiguration = WKWebViewConfiguration()
                                if Enviroment.shared.processPool == nil {
                                    Enviroment.shared.processPool = WKProcessPool()
                                }
                                webConfiguration.processPool = Enviroment.shared.processPool!
                                webConfiguration.processPool = WKProcessPool()
                                let webView = WKWebView(frame: .zero, configuration: webConfiguration)
                                webView.navigationDelegate = self
                                return webView
                            }()

                         

                        Setting WKProcessPool is the most important step here. WKWebview makes use of process isolation - which means it runs on a different process than the process of your app. This can sometimes cause conflict and prevent your cookie from being synced properly with the WKWebview. If you don't use the same instance of WKProcessPool each time you configure a WKWebView for the same domain (maybe you have a VC A that contains a WKWebView and you want to create different instances of VC A in different places), there can be conflict setting cookies. To solve the problem, after the first creation of the WKProcessPool for a WKWebView that loads domain B, I save it in a singleton and use that same WKProcessPool every time I have to create a WKWebView that loads the same domain B

                         

                        After the initialization process, you can load an URLRequest inside the completion block of httpCookieStore.setCookie. Here, you have to attach the cookie to the request header otherwise it won't work.

                         

                            mainWebView.configuration.websiteDataStore.httpCookieStore.setCookie(your_cookie) {
                                    self.mainWebView.load(your_request, with: [your_cookie])
                            }
                        
                        
                            extension WKWebView {
                               func load(_ request: URLRequest, with cookies: [HTTPCookie]) {
                                  var request = request
                                  let headers = HTTPCookie.requestHeaderFields(with: cookies)
                                  for (name, value) in headers {
                                     request.addValue(value, forHTTPHeaderField: name)
                                  }      
                                  load(request)
                               }
                            }
                        • Re: Setting cookies with WKHTTPCookieStorage do not sync with wkwebview
                          nortan.nathan Level 1 Level 1 (0 points)

                          I have a similar problem. I used to sync HTTPCookieStorage with WKHTTPCookieStore but my cookies not saved and every time it return logout user.