首先,最近有個想法是讓UIWebview支持webp,那麼原生的webview引擎是不支持的,因此就有了如標題所寫的想法。其實不只僅侷限於爲了讓其支持webp,若是能讓webview的圖片請求都走向本身實現的圖片庫,那麼能夠實現不少不少黑科技(好比每一個圖片加個app特定水印?或者說裁剪圖片使webview能有更好的性能表現?不少不少的功能,不一一列舉了)。javascript
上述說的cache策略是創建在你正確理解而且用好的NSURLRequestCachePolicy的前提下的。爲何這麼說呢?有些人會濫用NSURLRequestCachePolicy ,好比明明NSURLRequestReloadIgnoringLocalCacheData,卻說怎麼沒緩存,這就有點蛋疼了。關於cache策略能夠看看官方文檔,比我說的清楚多了~html
#總結下:
不管採用哪一種NSURLRequestCachePolicy,在請求的時候都會cache。而在下次請求(不包括[webview reload]
,刷新會強制從新發請求)的時候,則會根據NSURLRequestCachePolicy的策略決定是否拿緩存。若是是NSURLRequestUseProtocolCachePolicy,還要根據對應的協議(http\https\ftp)的服務端提供的response來決定。前端
其實思路挺簡單的,在以前介紹hybrid app的時候,已經介紹了NSURLProtocol這個神器的做用。這裏其實也是用NSURLProtocol來達到目的。
想想,無非就是攔截掉webview的請求,將自己在webview的URL Load System的請求抽出來,咱們本身處理掉,而後組裝成response返回給webview。對於webview而言是徹底透明的,它不關心中途的網絡請求是如何完成的,它只知道它發出了請求,而且收到response便可。
換句話說即咱們本身處理整個請求的全部過程。
以下圖所示:java
簡簡單單看一下原理是很簡單,可是就是由於這小小的動做咱們能夠作到不少本來無法讓webview作到的事情。git
支持webp:將圖片請求在本身實現的圖片庫中完成,而後轉成webview支持的data格式透傳回去便可。github
緩存:咱們都知道系統的緩存是不可靠的,不少開發者會採用本身的緩存策略,而webview的請求若是不進行干預是無法作到走咱們本身的緩存策略的,可是如文章所說,便可作到。web
圖片尺寸優化:每每對於H5而言,若是前端開發者沒有注意圖片尺寸問題,在PC和手機上圖片都採用一個尺寸的話,這是十分很差的,手機屏幕小並不須要這麼大尺寸的圖。每每大多數的圖片CDN都是會支持裁剪的,而攔截圖片請求在URL上拼接size是一個解決方式。緩存
還有許許多多的功能,好比開頭提到的水印,從我這個app打開的圖片都被我加上了本app的icon,是否是很屌。網絡
這裏有個小插曲:在擼demo的時候,我本想讓demo中的SDWebImage請求同一個圖片,結果發現怎麼也走不到protocol中。搞了半天無法只能去看文檔,發現以下:app
NSURLSession與NSURLConnection註冊NSURLProtocol的方式是不一樣的!
+ (BOOL)canInitWithRequest:(NSURLRequest *)request {
NSString *path = request.URL.path;
// 只處理是圖片的URL請求
if ([path hasSuffix:@".jpg"] || [path hasSuffix:@".jpeg"] || [path hasSuffix:@".webp"]) {
if ([NSURLProtocol propertyForKey:WebviewImageProtocolHandledKey inRequest:request]) {
return NO;
}
return YES;
}
return NO;
}
+ (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request {
return request;
}
- (void)startLoading {
// 將本地的緩存組裝成報文傳回去
NSData *data = [self imageDataWithURL:self.request.URL];
if (data) {
NSString *mimeType = @"image/jpeg";
NSMutableDictionary *header = [[NSMutableDictionary alloc] initWithCapacity:2];
NSString *contentType = [mimeType stringByAppendingString:@";charset=UTF-8"];
header[@"Content-Type"] = contentType;
header[@"Content-Length"] = [NSString stringWithFormat:@"%lu", (unsigned long) data.length];
NSHTTPURLResponse *httpResponse = [[NSHTTPURLResponse alloc] initWithURL:self.request.URL
statusCode:200
HTTPVersion:@"1.1"
headerFields:header];
[self.client URLProtocol:self didReceiveResponse:httpResponse cacheStoragePolicy:NSURLCacheStorageNotAllowed];
[self.client URLProtocol:self didLoadData:data];
[self.client URLProtocolDidFinishLoading:self];
} else {
// 這裏其實應該是圖片庫對於圖片請求的處理,每一個人實現的圖片庫不同,因此我就直接以webview的方式請求了
NSMutableURLRequest *newRequest = [self.request mutableCopy];
newRequest.allHTTPHeaderFields = self.request.allHTTPHeaderFields;
[NSURLProtocol setProperty:@YES forKey:WebviewImageProtocolHandledKey inRequest:newRequest];
self.connection = [NSURLConnection connectionWithRequest:newRequest delegate:self];
}
}
- (void)stopLoading {
[self.connection cancel];
}
- (NSData*)imageDataWithURL:(NSURL*)url {
// 僞裝這是一個緩存,這裏拋磚引玉下,你們能夠本身實現本身的圖片緩存策略
if ([url.absoluteString isEqualToString:@"http://kuailejim.com/images/background-cover.jpg"]) {
NSString *filePath = [[NSBundle mainBundle] pathForResource:@"background-cover" ofType:@"jpg"];
NSData *data = [NSData dataWithContentsOfFile:filePath];
return data;
}
return nil;
}複製代碼
因爲每一個開發團隊可能有本身的圖片處理庫,因此我這裏就只給出簡單的思路,你們能夠自行按照本身的圖片庫替代上述有註釋的代碼。
能夠很明顯的看出,圖片請求沒了,由於走了本地的緩存。
本文只給出瞭如何進行網絡請求替換,而且給出一個小demo,其實能作的遠遠不止這些。正如文中所說webp,圖片尺寸優化等等,若是你感興趣也能夠本身擼一個demo玩玩~