WKHTTPCookieStore HTTPCookieStorage同步类 [英] WKHTTPCookieStore HTTPCookieStorage synchronization class

查看:24
本文介绍了WKHTTPCookieStore HTTPCookieStorage同步类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

用例:我有两个WKWebView,一个在主应用程序中,另一个在应用程序扩展中。我希望它们共享同一个Cookie存储区。

Apple API有两个不同的Cookie存储类:WKHTTPCookieStoreHTTPCookieStorage

Apple还有sharedCookieStorage(forGroupContainerIdentifier identifier: String) -> HTTPCookieStorageforURLSessions(非WKWebViews)可跨应用程序/生成目标/扩展使用。

我的计划是将一个WKWebKitCookie传输到sharedCookieStorage,然后再传输到另一个WKWebKitCookie存储区。

在我编写之前,有没有人有一个简单的包装类来接受、观察并保持它们的同步?

或者有没有其他更简单的方法来完成这一看似非常常见的用例?

推荐答案

这是我放在一起的。需要牢记的重要事项:

  • WKWebViewCookie是异步设置和获取的,因此回调次数
  • 有一个观察者类附加到WKHTTPCookieStore。它并不完美,但有cookiesDidChange方法可用于手动更新,比如在页面加载后
  • 您应该在addCookieStore回调中实例化并加载WKWebView,以确保在加载页面之前同步存储
  • 添加的存储区最初与添加的第一个存储区同步。您应该嵌套addCookieStore回调以确保正确的顺序

(很抱歉,由于兼容性原因,我无法使用合并)

编码:

import WebKit
import Foundation

class CookieSync : NSObject, WKHTTPCookieStoreObserver {
    var wkStores = [WKHTTPCookieStore]();
    var sessionStores = [HTTPCookieStorage]();
    
    static let debug = false
    
    //The first store added is the canon
    func addCookieStore(_ store: WKHTTPCookieStore, callback:(()->())?) {
        wkStores.append(store)
        
        store.getAllCookies { (cookies) in
            if CookieSync.debug { print("Adding WK:(cookies.count)") }
            store.add(self)
            if self.sessionStores.count > 0 {
                self.synchronizeAll(self.sessionStores[0]) {
                    store.getAllCookies { (cookies) in
                        if CookieSync.debug { print("Added WK:(cookies.count)") }
                        callback?()
                    }
                }
            } else if self.wkStores.count > 1 {
                self.synchronizeAll(self.wkStores[0]) {
                    store.getAllCookies { (cookies) in
                        if CookieSync.debug { print("Added WK:(cookies.count)") }
                        callback?()
                    }
                }
            } else {
                callback?()
            }
        }
    }
    
    //The first store added is the canon
    func addCookieStore(_ store: HTTPCookieStorage, callback:(()->())?) {
        sessionStores.append(store)
        if CookieSync.debug { print("Adding S:(store.cookies?.count ?? 0)") }
        
        if wkStores.count > 0 {
            synchronizeAll(wkStores[0]) {
                if CookieSync.debug { print("Added S:(store.cookies?.count ?? 0)") }
                callback?()
            }
        } else if sessionStores.count > 1 {
            synchronizeAll(sessionStores[0]) {
                if CookieSync.debug { print("Added S:(store.cookies?.count ?? 0)") }
                callback?()
            }
        } else {
            callback?()
        }
    }
    
    //There is no Observer callback for HTTPCookieStorage
    func cookiesDidChange(in cookieStore: HTTPCookieStorage) {
        synchronizeAll(cookieStore) {
            if CookieSync.debug { print("Synced S:(cookieStore.cookies?.count ?? 0)") }
        }
    }
    
    func cookiesDidChange(in cookieStore: WKHTTPCookieStore) {
        synchronizeAll(cookieStore) {
            cookieStore.getAllCookies { (cookies) in
                if CookieSync.debug { print("Synced WK:(cookies.count)") }
                for cookie in cookies {
                    if CookieSync.debug { print("(cookie.name) = (cookie.value)") }
                }
            }
        }
    }
    
    //Private
    fileprivate func synchronizeAll(_ to: WKHTTPCookieStore, callback:(()->())?) {

        let dispatch = DispatchGroup()
        let queue = Thread.isMainThread ? DispatchQueue.main : DispatchQueue(label: "cookie_sync1")
    
        for store in self.wkStores {
            if store == to { continue }
            
            dispatch.enter()
            self.removeAllCookies(store) {
            
                dispatch.enter()
                to.getAllCookies { (cookies) in
                    for cookie in cookies {
                        dispatch.enter()
                        store.setCookie(cookie) {
                            dispatch.leave()
                        }
                    }
                    dispatch.leave()
                }
                dispatch.leave()
            }
        
        }
        
        for store in self.sessionStores {
            self.removeAllCookies(store)
            
            dispatch.enter()
                to.getAllCookies { (cookies) in
                    for cookie in cookies {
                        store.setCookie(cookie)
                    }
                    dispatch.leave()
                }
        }
    
    
        dispatch.notify(queue: queue) {
            callback?()
        }
    }
    
    fileprivate func synchronizeAll(_ to: HTTPCookieStorage, callback:(()->())?) {

        guard let cookies = to.cookies else { callback?(); return; }
        
        let queue = Thread.isMainThread ? DispatchQueue.main : DispatchQueue(label: "cookie_sync2")
        let dispatch = DispatchGroup()
        
        for store in self.sessionStores {
            if store == to { continue }
            
            self.removeAllCookies(store)

            for cookie in cookies {
                store.setCookie(cookie)
            }
        }
        
        for store in self.wkStores {

            dispatch.enter()
            self.removeAllCookies(store) {
                
                for cookie in cookies {
                    dispatch.enter()
                    store.setCookie(cookie) {
                        dispatch.leave()
                    }
                }
                dispatch.leave()
            }
        }
        
        dispatch.notify(queue: queue) {
            callback?()
        }
    }
    
    fileprivate func removeAllCookies(_ store: WKHTTPCookieStore, callback:(()->())?) {
        let queue = Thread.isMainThread ? DispatchQueue.main : DispatchQueue(label: "cookie_delete")
        
        let dispatch = DispatchGroup()
        
        dispatch.enter()
        store.getAllCookies { (cookies) in
            for cookie in cookies {
                dispatch.enter()
                store.delete(cookie) {
                    dispatch.leave()
                }
            }
            dispatch.leave()
        }
        dispatch.notify(queue: queue) {
            callback?()
        }
    }
    
    fileprivate func removeAllCookies(_ store: HTTPCookieStorage) {
        guard let cookies = store.cookies else { return }
        for cookie in cookies {
            store.deleteCookie(cookie)
        }
    }
}

这篇关于WKHTTPCookieStore HTTPCookieStorage同步类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆