75

Any one worked with WKWebView and tried to clear cache? If yes, how to do it? Any example?

P.S. : Normal NSURLCache is not working.

Pang
  • 9,564
  • 146
  • 81
  • 122
Sravan
  • 1,891
  • 4
  • 23
  • 28

14 Answers14

78

Updated Swift 5 version:

WKWebsiteDataStore.default().removeData(ofTypes: [WKWebsiteDataTypeDiskCache, WKWebsiteDataTypeMemoryCache], modifiedSince: Date(timeIntervalSince1970: 0), completionHandler:{ })

Swift version:

if #available(iOS 9.0, *) {
  let websiteDataTypes = NSSet(array: [WKWebsiteDataTypeDiskCache, WKWebsiteDataTypeMemoryCache])
  let date = NSDate(timeIntervalSince1970: 0)
  WKWebsiteDataStore.defaultDataStore().removeDataOfTypes(websiteDataTypes as! Set<String>, modifiedSince: date, completionHandler:{ })
} else {
    var libraryPath = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.LibraryDirectory, NSSearchPathDomainMask.UserDomainMask, false).first!
    libraryPath += "/Cookies"

    do {
      try NSFileManager.defaultManager().removeItemAtPath(libraryPath)
    } catch {
      print("error")
    }
    NSURLCache.sharedURLCache().removeAllCachedResponses()
}

Swift 3 version:

   if #available(iOS 9.0, *)
    {
        let websiteDataTypes = NSSet(array: [WKWebsiteDataTypeDiskCache, WKWebsiteDataTypeMemoryCache])
        let date = NSDate(timeIntervalSince1970: 0)
        
        WKWebsiteDataStore.default().removeData(ofTypes: websiteDataTypes as! Set<String>, modifiedSince: date as Date, completionHandler:{ })
    }
    else
    {
        var libraryPath = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.libraryDirectory, FileManager.SearchPathDomainMask.userDomainMask, false).first!
        libraryPath += "/Cookies"
        
        do {
            try FileManager.default.removeItem(atPath: libraryPath)
        } catch {
            print("error")
        }
        URLCache.shared.removeAllCachedResponses()
    }
Arsonik
  • 2,276
  • 1
  • 16
  • 24
Esqarrouth
  • 38,543
  • 21
  • 161
  • 168
  • 2
    Nice, thank you. Swift (2.0 at least) allows inference and simplification on types: `let types = Set([WKWebsiteDataTypeDiskCache, WKWebsiteDataTypeMemoryCache])` and then no bridging needed in `remove` call – BaseZen Jun 01 '16 at 01:29
  • I'm wondering if anyone actually tried the < 9.0 version. This always spews an error. Change the last parameter of `NSSearchPathForDirectoriesInDomains` to `true` and it worked for me. – funct7 Sep 24 '16 at 19:14
  • Even with iOS 9.0 available, It seems like WKWebsiteDataStore.default().removeData... doesn't remove site manifest file resources. I had to use both WKWebsiteDataStore.default().removeData and URLCache.shared.removeAllCachedResponses() – Rodrigo Fava Dec 05 '18 at 18:59
  • @Esqarrouth can you help me for some kind of issue in WKWebView ? – Virani Vivek Apr 03 '19 at 07:00
  • 2
    Why are you initiating as `NSSet` and then forced casting to `Set`? You can just initiate as a Set directly: `let types = Set([WKWebsiteDataTypeDiskCache, WKWebsiteDataTypeMemoryCache])` – David Seek Mar 15 '21 at 02:46
66

In iOS 9

// Optional data
NSSet *websiteDataTypes
= [NSSet setWithArray:@[
                        WKWebsiteDataTypeDiskCache,
                        //WKWebsiteDataTypeOfflineWebApplicationCache,
                        WKWebsiteDataTypeMemoryCache,
                        //WKWebsiteDataTypeLocalStorage,
                        //WKWebsiteDataTypeCookies,
                        //WKWebsiteDataTypeSessionStorage,
                        //WKWebsiteDataTypeIndexedDBDatabases,
                        //WKWebsiteDataTypeWebSQLDatabases,
                        //WKWebsiteDataTypeFetchCache, //(iOS 11.3, *)
                        //WKWebsiteDataTypeServiceWorkerRegistrations, //(iOS 11.3, *)
                        ]];
// All kinds of data
// NSSet *websiteDataTypes = [WKWebsiteDataStore allWebsiteDataTypes];
// Date from
NSDate *dateFrom = [NSDate dateWithTimeIntervalSince1970:0];
// Execute
[[WKWebsiteDataStore defaultDataStore] removeDataOfTypes:websiteDataTypes modifiedSince:dateFrom completionHandler:^{
   // Done
}];
Snowman
  • 31,411
  • 46
  • 180
  • 303
Shingo Fukuyama
  • 1,492
  • 1
  • 17
  • 19
  • 1
    Worked beautifully. Remember to do this: #import – hnilsen Sep 12 '16 at 12:01
  • this code presents the compile error: `Initializer element is not a compile-time constant` – andrepaulo May 18 '17 at 21:28
  • I just want to point out even though the above code is good, it didn't work for me for the website I was visiting using the WKWebView (the website is also under development) But the selected answer in this question worked: https://stackoverflow.com/questions/31289838/how-to-delete-wkwebview-cookies – C0D3 Nov 13 '17 at 16:07
30

Remove Cache and Cookies

# WKWebView+Clean.swift

import WebKit

extension WKWebView {
    class func clean() {
        guard #available(iOS 9.0, *) else {return}

        HTTPCookieStorage.shared.removeCookies(since: Date.distantPast)

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

Example:

import WebKit
...
WKWebview.clean()
Peter Kreinz
  • 7,979
  • 1
  • 64
  • 49
6

I was able to solve this issue by having my WKWebView evaluate window.location.reload. I have a tap gesture recognizer on the web view and whenever it detects a double tap with 2 touches, I run the following:

webView.evaluateJavaScript("window.location.reload(true)", completionHandler: nil);

Hope this helps.

harrisonlee
  • 5,068
  • 4
  • 21
  • 20
4

You cannot delete caches only with NSURLCache. After much cut-and-try, I could clear caches by the following steps (as of iOS 8.1.1):

  1. Use NSURLCache to delete caches in the same way as you used to do on UIWebView. If you use WKProccessPool, re-initialize it.
  2. Delete Caches directory in Library.
  3. Delete all WKWebViews

Next time you create WKWebView, caches should be cleared.

ShingoFukuyama/WKWebViewTips

Shingo Fukuyama
  • 1,492
  • 1
  • 17
  • 19
3

swift5

URLCache.shared.removeAllCachedResponses()
Kseniya
  • 97
  • 1
  • 2
3

This one-liner should do the trick by removing all WKWebView data.

WKWebsiteDataStore.default().removeData(ofTypes: WKWebsiteDataStore.allWebsiteDataTypes(), modifiedSince: Date(timeIntervalSince1970: 0), completionHandler: {})
atulkhatri
  • 10,896
  • 3
  • 53
  • 89
2

Something similar for iOS 9.0 and later:

let store: WKWebsiteDataStore = WKWebsiteDataStore.default()
let dataTypes: Set<String> = WKWebsiteDataStore.allWebsiteDataTypes()
store.fetchDataRecords(ofTypes: dataTypes, completionHandler: { (records: [WKWebsiteDataRecord]) in
  store.removeData(ofTypes: dataTypes, for: records, completionHandler: {
    // do your thing here
  })
})
nouatzi
  • 735
  • 4
  • 14
2

Worked
Swift 3. Version.
For Older Version Swift

import Foundation
import WebKit

func removeWebData() {

    if #available(iOS 9.0, *) {

        let websiteDataTypes = WKWebsiteDataStore.allWebsiteDataTypes()
        let date = NSDate(timeIntervalSince1970: 0)

        WKWebsiteDataStore.default().removeData(ofTypes: websiteDataTypes, modifiedSince: date as Date, completionHandler: {
            #if DEBUG

                print("remove all data in iOS9 later")

            #endif
        })

    }else {

        // Remove the basic cache.
        URLCache.shared.removeAllCachedResponses()

        // Delete system cookie store in the app
        let storage = HTTPCookieStorage.shared
        if let cookies = storage.cookies {
            for cookie in cookies {
                storage.deleteCookie(cookie)
            }
        }


        do {
            // folder 를 삭제하는 대신 contents 를 삭제하는 이유?
            // MainVC 가 호출되면 cache, cookie가 발생하므로 로딩시 확인된 cache, cookie 폴더의
            // contents 에 대해서만 삭제 진행.

            // Clear web cache
            try deleteLibraryFolderContents(folder: "Caches")

            // Remove all cookies stored by the site. This includes localStorage, sessionStorage, and WebSQL/IndexedDB.
            try deleteLibraryFolderContents(folder: "Cookies")

            // Removes all app cache storage.
            try deleteLibraryFolder(folder: "WebKit")

        } catch {
            #if DEBUG

                print("Delete library folders error in iOS9 below")

            #endif

        }
    }
}

/**
 Delete folder in library

 - parameter folder: a folder you want to delete

 - throws: throws an error
 */
func deleteLibraryFolder(folder: String) throws {
    let manager = FileManager.default
    let library = manager.urls(for: .libraryDirectory, in: .userDomainMask).first!
    let dir = library.appendingPathComponent(folder)
    try manager.removeItem(at: dir)
}

/**
 Delete contents in library folder

 - parameter folder: target folder

 - throws: throws an error
 */
private func deleteLibraryFolderContents(folder: String) throws {
    let manager = FileManager.default
    let library = manager.urls(for: FileManager.SearchPathDirectory.libraryDirectory, in: .userDomainMask)[0]
    let dir = library.appendingPathComponent(folder)
    let contents = try manager.contentsOfDirectory(atPath: dir.path)
    for content in contents {
        do {
            try manager.removeItem(at: dir.appendingPathComponent(content))
        } catch where ((error as NSError).userInfo[NSUnderlyingErrorKey] as? NSError)?.code == Int(EPERM) {
            // "EPERM: operation is not permitted". We ignore this.
            #if DEBUG

                print("Couldn't delete some library contents.")

            #endif
        }
    }
}
ZAFAR007
  • 3,049
  • 1
  • 34
  • 45
2
private func deleteCache(){
        if #available(iOS 9.0, *) {
          let websiteDataTypes = NSSet(array: [WKWebsiteDataTypeDiskCache, WKWebsiteDataTypeMemoryCache])
          let date = NSDate(timeIntervalSince1970: 0)
            WKWebsiteDataStore.default().removeData(ofTypes: websiteDataTypes as! Set<String>, modifiedSince: date as Date, completionHandler:{ })
        } else {
            var libraryPath = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.libraryDirectory, FileManager.SearchPathDomainMask.userDomainMask, false).first!
            libraryPath += "/Cookies"

            do {
                try FileManager.default.removeItem(atPath: libraryPath)
            } catch {
              print("error")
            }
            URLCache.shared.removeAllCachedResponses()
        }
    }
1

It works for me

 if #available(iOS 9.0, *) {
            let websiteDataTypes = NSSet(array: [WKWebsiteDataTypeDiskCache, WKWebsiteDataTypeMemoryCache])
            let date = NSDate(timeIntervalSince1970: 0)
            WKWebsiteDataStore.defaultDataStore().removeDataOfTypes(websiteDataTypes as! Set<String>, modifiedSince: date, completionHandler:{ })
        }
        else
        {
          NSURLCache.sharedURLCache().removeAllCachedResponses()
        }
Durai Amuthan.H
  • 31,670
  • 10
  • 160
  • 241
1

Swift 3.x version of @Esqarrouth's post

func clearCache() {
    if #available(iOS 9.0, *) {
        let websiteDataTypes = NSSet(array: [WKWebsiteDataTypeDiskCache, WKWebsiteDataTypeMemoryCache])
        let date = NSDate(timeIntervalSince1970: 0)
        WKWebsiteDataStore.default().removeData(ofTypes: websiteDataTypes as! Set<String>, modifiedSince: date as Date, completionHandler:{ })
    } else {
        var libraryPath = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.libraryDirectory, FileManager.SearchPathDomainMask.userDomainMask, false).first!
        libraryPath += "/Cookies"

        do {
            try FileManager.default.removeItem(atPath: libraryPath)
        } catch {
            print("error")
        }
        URLCache.shared.removeAllCachedResponses()
    }
}
zingle-dingle
  • 1,681
  • 16
  • 16
1

It takes me a few hours, but this works for me! After the loadRequest, I make a reloadFromOrigin! So I force empty cache! [WKWebView loadRequest:request]; [WKWebView reloadFromOrigin];

1

get the cache dictionary path and delete it

   NSFileManager *fileManager = [NSFileManager defaultManager];
   NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0];
  NSError *error;
  BOOL success = [fileManager removeItemAtPath:documentsPath error:&error];
    NSLog(@"%d",success);
Sateesh Pasala
  • 772
  • 8
  • 15