如何删除WKWebview的cookies

43

目前我是这样做的

    NSHTTPCookie *cookie;
    NSHTTPCookieStorage *storage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
    for (cookie in [storage cookies])
    {
        [storage deleteCookie:cookie];
    }

但是它在iOS 8上无法正常工作,64位设备。

有没有其他方法可以清除WKWebview的Cookie?非常感谢您的帮助。

14个回答

62

苹果发布了适用于 iOS 9 及更高版本的新 API,因此现在我们可以使用以下代码删除存储在 WKWebView 中的特定域的 cookie。

Swift 4/5 版本:

let dataStore = WKWebsiteDataStore.default()
dataStore.fetchDataRecords(ofTypes: WKWebsiteDataStore.allWebsiteDataTypes()) { records in
  dataStore.removeData(
    ofTypes: WKWebsiteDataStore.allWebsiteDataTypes(),
    for: records.filter { $0.displayName.contains("facebook") },
    completionHandler: completion
  )
}

以下是 Swift 3 版本
let dataStore = WKWebsiteDataStore.default()
    dataStore.fetchDataRecords(ofTypes: WKWebsiteDataStore.allWebsiteDataTypes()) { (records) in
        for record in records {
            if record.displayName.contains("facebook") {
                dataStore.removeData(ofTypes: WKWebsiteDataStore.allWebsiteDataTypes(), for: [record], completionHandler: {
                    print("Deleted: " + record.displayName);
                })
            }
        }
    }

Objective-C版本 -

WKWebsiteDataStore *dateStore = [WKWebsiteDataStore defaultDataStore];
[dateStore
   fetchDataRecordsOfTypes:[WKWebsiteDataStore allWebsiteDataTypes]
   completionHandler:^(NSArray<WKWebsiteDataRecord *> * __nonnull records) {
     for (WKWebsiteDataRecord *record  in records) {
       if ( [record.displayName containsString:@"facebook"]) {
         [[WKWebsiteDataStore defaultDataStore]
             removeDataOfTypes:record.dataTypes
             forDataRecords:@[record]
             completionHandler:^{
               NSLog(@"Cookies for %@ deleted successfully",record.displayName);
             }
         ];
       }
     }
   }
 ];

以上代码片段肯定适用于 iOS 9 及以后的版本。不幸的是,如果我们在 iOS 9 之前的版本中使用 WKWebView,我们仍然必须坚持传统的方法并按以下方式删除所有 cookie 存储。
NSString *libraryPath = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *cookiesFolderPath = [libraryPath stringByAppendingString:@"/Cookies"];
NSError *errors;
[[NSFileManager defaultManager] removeItemAtPath:cookiesFolderPath error:&errors];

使用这种方法只返回域级别,即facebook.com,它告诉我里面有cookie。但我无法删除或检索单个项目。例如,Facebook内部的会话cookie。旧方法会将所有cookie压缩成一个列表。这是设计如此还是我漏掉了什么?我找不到任何信息。- @pankaj - Woodmister1
你尝试过移除类型为 WKWebsiteDataTypeSessionStorage 的记录吗? - Pankaj Gaikar
不幸的是,它被用作cookie,在Safari中进行调试显示我有两个域名与使用cookie、本地存储等其他项目的数量一起存储。在HTTPCookieStore下,您可以看到跨所有域的平面列表的cookie列表。我想要的这个会话cookie就在其中。但是在通过这个新的DataStore请求时却没有看到它。然而,我确实看到了这两个域名项。所以好像我需要再深入一层。 - Woodmister1
@PankajGaikar 有没有一种方法可以从一个域名中删除特定的 cookies? - Crystal
@Crystal 很抱歉回复晚了。我没有特别做过这个,但我认为你可以通过搜索带有名称的cookie来实现。 - Pankaj Gaikar
1
请注意,与NSHTTPCookieStorage不同,必须在主线程上调用WebKit API。如果您要在后台线程中清除Cookie,则需要使用NSHTTPCookieStorage。 - IGx89

24

Sarat的答案的Swift 3版本:

let dataStore = WKWebsiteDataStore.default()
dataStore.fetchDataRecords(ofTypes: WKWebsiteDataStore.allWebsiteDataTypes()) { (records) in
    for record in records {
        if record.displayName.contains("facebook") {
            dataStore.removeData(ofTypes: WKWebsiteDataStore.allWebsiteDataTypes(), for: [record], completionHandler: {
                print("Deleted: " + record.displayName);
            })
        }
    }
}

22

支持 iOS 11.0 及以上版本

以下解决方案适用于我:

第1步。从HTTPCookieStorage中删除Cookie。

第2步。从WKWebsiteDataStore中获取数据记录并删除它们。

第3步。创建一个新的WKProcessPool

创建 WKWebView 扩展:

extension WKWebView {

    func cleanAllCookies() {
        HTTPCookieStorage.shared.removeCookies(since: Date.distantPast)
        print("All cookies deleted")

        WKWebsiteDataStore.default().fetchDataRecords(ofTypes: WKWebsiteDataStore.allWebsiteDataTypes()) { records in
            records.forEach { record in
                WKWebsiteDataStore.default().removeData(ofTypes: record.dataTypes, for: [record], completionHandler: {})
                print("Cookie ::: \(record) deleted")
            }
        }
    }

    func refreshCookies() {
        self.configuration.processPool = WKProcessPool()
    }
}

使用方法:

override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(true)
        webView.cleanAllCookies()
        webView.refreshCookies()
    }

6

这些选项都对我没用,但我找到了一个有效的解决方案:

let config = WKWebViewConfiguration()
if #available(iOS 9.0, *) {
    config.websiteDataStore = WKWebsiteDataStore.nonPersistentDataStore()
} else {
     // I have no idea what to do for iOS 8 yet but this works in 9.
}

let webView = WKWebView(frame: .zero, configuration: config)

使用此存储时,您正在使用“私有模式”,其中localStorage和其他内容将不可用,因此您的JavaScript可能会失败,但是它确实会清除所有内容。 - Salavert

5

iOS9中:

//// Optional data
NSSet *websiteDataTypes
= [NSSet setWithArray:@[
                        WKWebsiteDataTypeDiskCache,
                        //WKWebsiteDataTypeOfflineWebApplicationCache,
                        WKWebsiteDataTypeMemoryCache,
                        //WKWebsiteDataTypeLocalStorage,
                        //WKWebsiteDataTypeCookies,
                        //WKWebsiteDataTypeSessionStorage,
                        //WKWebsiteDataTypeIndexedDBDatabases,
                        //WKWebsiteDataTypeWebSQLDatabases
                        ]];
//// All kinds of data
//NSSet *websiteDataTypes = [WKWebsiteDataStore allWebsiteDataTypes];
//// Date from
NSDate *dateFrom = [NSDate dateWithTimeIntervalSince1970:0];
//// Execute
[[WKWebsiteDataStore defaultDataStore] removeDataOfTypes:websiteDataTypes modifiedSince:dateFrom completionHandler:^{
    // Done
    NSLog(@"remove done");
}];

3
建立在所有现有答案之上,如果您想要清除特定 WKWebView 实例“webView”的 cookie 和数据记录,而不是默认的储存的 cookie 和数据记录,您可以使用以下代码:
let dataStore = webView.configuration.websiteDataStore
let cookieStore = dataStore.httpCookieStore
cookieStore.getAllCookies {
    $0.forEach { cookie in
        cookieStore.delete(cookie)
    }
}
dataStore.fetchDataRecords(ofTypes: WKWebsiteDataStore.allWebsiteDataTypes()) { records in
    records.forEach { record in
        dataStore.removeData(ofTypes: record.dataTypes, for: [record]) { }
    }
}

2

Swift 4 和更短的版本:

let dataStore = WKWebsiteDataStore.default()
dataStore.fetchDataRecords(ofTypes: WKWebsiteDataStore.allWebsiteDataTypes()) { records in
    dataStore.removeData(ofTypes: WKWebsiteDataStore.allWebsiteDataTypes(),
                         for: records.filter { $0.displayName.contains("facebook") },
                         completionHandler: completion)
}

2

Swift 5

    /// old API cookies
    for cookie in HTTPCookieStorage.shared.cookies ?? [] {
        HTTPCookieStorage.shared.deleteCookie(cookie)
    }
    /// URL cache
    URLCache.shared.removeAllCachedResponses()
    /// WebKit cache
    let date = Date(timeIntervalSince1970: 0)
    WKWebsiteDataStore.default().removeData(
        ofTypes: WKWebsiteDataStore.allWebsiteDataTypes(),
        modifiedSince: date,
        completionHandler:{})

1
除了清除共享 cookie 存储中的 cookie 外,我建议尝试清除缓存 (NSURLCache),丢弃 WKWebView 并创建一个新的带有新的 WKProcessPool 的 WKWebView。

很抱歉,但这个好像也不起作用。我在某个地方读到,我还需要从设备中删除本地库,我也会尝试这样做。 - Pankaj Gaikar
如果您使用WKProcessPool技巧(来自https://dev59.com/vlwX5IYBdhLWcg3w-Thv#33198799)在多个WKWebView之间共享cookie,则需要像答案中一样创建一个新的WKProcessPool。 - Peacemoon

0

看起来在iOS 8.2中现在使用NSHTTPCookieStorage正确清除cookie,这是必需的。我已经发布了一个应用程序,在打开基于WKWebView的登录之前运行此代码:

NSHTTPCookieStorage *storage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
for (NSHTTPCookie *cookie in [storage cookies])
{
    [storage deleteCookie:cookie];
}

在 iOS 8.2 之前,该网站会使用保存的 cookie 自动登录,现在它会正确地要求用户重新登录。所有这些都发生在我没有更新应用程序的情况下。:)


这并没有什么意义,你的代码和我的一样,虽然我也尝试了这段代码。不行,这个对我也不起作用。 - Pankaj Gaikar
好的,没问题,我会等待你的回答。 - Rohit suvagiya
现在,我一头雾水,不知道这里发生了什么,但仍会尝试一些解决方法。 - Pankaj Gaikar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接