近期公司樓下實體店的網絡及其不穩定,經常有用戶反饋App里的網頁打開特別慢,進度條一直加載不完,體驗很差,於是就有了webview緩存的需求,項目里使用的是WKWebView,而且蘋果早就不提倡使用UIWebView了,這里也不做贅述了。
-
WKWebView 支持的緩存策略枚舉
* 參見 蘋果官方文檔
typedef NS_ENUM(NSUInteger, NSURLRequestCachePolicy) { NSURLRequestUseProtocolCachePolicy = 0, // 默認策略,具體的緩存邏輯和協議的聲明有關,如果協議沒有聲明,不需要每次重新驗證cache。 NSURLRequestReloadIgnoringLocalCacheData = 1, // 忽略本地緩存,直接從后台請求數據 NSURLRequestReloadIgnoringLocalAndRemoteCacheData = 4, // iOS 13 實現,忽略本地緩存數據、代理和其他中介的緩存,直接從后台請求數據 NSURLRequestReloadIgnoringCacheData = NSURLRequestReloadIgnoringLocalCacheData NSURLRequestReturnCacheDataElseLoad = 2, // // 優先從本地拿數據,且忽略請求生命時長和過期時間。但是如果沒有本地cache,則請求源數據 NSURLRequestReturnCacheDataDontLoad = 3, //只從本地拿數據 NSURLRequestReloadRevalidatingCacheData = 5, // iOS 13才實現,從原始地址確認緩存數據的合法性后,緩存數據就可以使用,否則從原始地址加載。 };
-
WKWebView使用緩存方式:
// 使用默認策略舉例 NSURLRequest *request =[NSURLRequest requestWithURL:[NSURL URLWithString:self.urlString] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:20]; [_webView loadRequest:request];
我們需要注意一下
NSURLRequestReloadIgnoringLocalAndRemoteCacheData = 4
和NSURLRequestReloadRevalidatingCacheData = 5
在iOS13之前並未實現該協議,所以如果使用該協議一定要注意系統版本判斷。
官方文檔說明:
-
WKWebView 默認的緩存策略 NSURLRequestUseProtocolCachePolicy = 0
-
官方文檔關於HTTP和HTTPS的NSURLRequestUseProtocolCachePolicy決策樹如下圖:
-
如果沒有特殊需求,系統默認的緩存策略已經比較完善了。
官方文檔對默認緩存策略的說明:如果緩存不存在,則向服務器發起請求;如果緩存存在,且緩存response頭沒有指明每次都必須校驗資源更新,且緩存沒有過期,則系統會直接返回緩存,不會發起請求;如果緩存過期了或者要求每次請求都必須校驗資源更新,則發起一個校驗資源的請求,如果(服務器返回)資源有更新則使用服務器返回的最新數據,如果沒有更新則使用本地緩存。如果沒有特殊需求,系統默認的緩存策略已經比較完善了。
-
-
客戶端使用系統緩存
-
設置緩存策略,決定是否使用緩存(即使允許加載緩存,離線的時候,也只能顯示頁面,具體的數據緩存需要web端實現);
-
使用 NSURLProtocol 攔截js、css,圖片資源,但這種方式有一個問題,NSURLProtocol使用了私有API,有審核被拒的風險,項目中暫不推薦使用;
-
同服務器進行交互(緩存過期處理,以及web資源更新)。
WKWebView默認緩存策略遵循HTTP緩存協議,客戶端默認緩存行為實際上是由服務器控制的,客戶端和服務器通過HTTP請求頭和響應頭中的緩存字段來交流,進而影響客戶端的行為。下面幾個相關的請求頭和響應頭需要知道:
-
-
Cache-Control:max-age=xxxx,指明緩存過期時間
-
在第一次請求到服務器資源的時候,服務器需要使用Cache-Control這個響應頭來指定緩存策略,它的格式如下:Cache-Control:max-age=xxxx,這個頭指明緩存過期的時間
-
-
Last-Modified/If-Modified-Since,標識資源最后修改時間
-
Last-Modified 是由服務器返回響應頭,標識資源的最后修改時間.
If-Modified-Since 則由客戶端發送,標識客戶端所記錄的,資源的最后修改時間。服務器接收到帶有該請求頭的請求時,會使用該時間與資源的最后修改時間進行對比,如果發現資源未被修改過,則直接返回HTTP 304而不返回包體,告訴客戶端直接使用本地的緩存。否則響應完整的消息內容。
-
-
Etag/If-None-Match,標識資源是否更新
-
Etag 由服務器發送,告之當資源在服務器上的一個唯一標識符。
客戶端請求時,如果發現資源過期(使用Cache-Control的max-age),發現資源具有Etag聲明,這時請求服務器時則帶上If-None-Match頭,服務器收到后則與資源的標識進行對比,決定返回200或者304。
-
設置緩存策略代碼:
// 默認緩存策略 NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url]
cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:15]; -
客戶端WebView加載H5和服務器交互過程流程圖:
-
WKWebView緩存沙盒路徑:
-
WKWebView清除緩存
WKWebView,在iOS9以后提供了緩存管理類WKWebsiteDataStore,iOS9以前只能手動移除文件
WKWebsiteDataStore
提供了API獲取web緩存數據類型[WKWebsiteDataStore allWebsiteDataTypes];
-
WKWebView支持的緩存類型:
/** 清除WKWebView的緩存 在磁盤緩存上。 WKWebsiteDataTypeDiskCache, html離線Web應用程序緩存。 WKWebsiteDataTypeOfflineWebApplicationCache, 內存緩存。 WKWebsiteDataTypeMemoryCache, 本地存儲。 WKWebsiteDataTypeLocalStorage, Cookies WKWebsiteDataTypeCookies, 會話存儲 WKWebsiteDataTypeSessionStorage, IndexedDB數據庫。 WKWebsiteDataTypeIndexedDBDatabases, 查詢數據庫。 WKWebsiteDataTypeWebSQLDatabases */
-
WKWebView 清除指定類型緩存:
NSSet *websiteDataTypes= [NSSet setWithArray:@[ WKWebsiteDataTypeDiskCache, WKWebsiteDataTypeMemoryCache ]]; //清除所有的web信息 //NSSet *websiteDataTypes = [WKWebsiteDataStore allWebsiteDataTypes]; NSDate *dateFrom = [NSDate dateWithTimeIntervalSince1970:0]; [[WKWebsiteDataStore defaultDataStore] removeDataOfTypes:websiteDataTypes modifiedSince:dateFrom completionHandler:^{ }];
-
拓展閱讀: