自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

我是如何一步一步實(shí)現(xiàn)網(wǎng)頁(yè)離線緩存的?

移動(dòng)開(kāi)發(fā)
一個(gè)Hybrid APP,如何做離線緩存策略?也可以簡(jiǎn)單來(lái)說(shuō),你的APP只是一個(gè)殼,里面真正加載的內(nèi)容是H5,如果優(yōu)化加載內(nèi)容的速度?

一個(gè)Hybrid APP,如何做離線緩存策略?也可以簡(jiǎn)單來(lái)說(shuō),你的APP只是一個(gè)殼,里面真正加載的內(nèi)容是H5,如果優(yōu)化加載內(nèi)容的速度?

先了解一下NSURLProtocol

從面意思看它是一個(gè)協(xié)議,但是它其實(shí)是一個(gè)類,而且繼承自NSObject。它的作用是處理特定URL協(xié)議的加載。它本身是一個(gè)抽象類,提供了使用特性URL方案處理URL的基礎(chǔ)結(jié)構(gòu)。你可以自己創(chuàng)建NSURLProtocol的子類,來(lái)讓自己的應(yīng)用支持自定義的協(xié)議或者URL方案。

我是如何一步一步實(shí)現(xiàn)網(wǎng)頁(yè)離線緩存的?

應(yīng)用程序永遠(yuǎn)不需要直接實(shí)例化一個(gè)NSURLProtocol子類。當(dāng)一個(gè)下載開(kāi)始的時(shí)候,系統(tǒng)創(chuàng)建一個(gè)合適的protoco對(duì)象來(lái)響應(yīng)URL請(qǐng)求。你要做的就是自己定義一個(gè)你自己的protocol,然后在APP啟動(dòng)的時(shí)候調(diào)用registerClass:,讓系統(tǒng)知道你的協(xié)議。

這里需要注意:你不能在watchOS 2以及更高版本中自定義URL scheme和協(xié)議。

為了支持特定的自定義請(qǐng)求,你***定義NSURLRequest 或者NSMutableURLRequest。讓自定義的這些對(duì)象來(lái)實(shí)現(xiàn)請(qǐng)求,這里需要使用NSURLProtocol的propertyForKey:inRequest:和setProperty:forKey:inRequest,然后你可以自定義NSURLResponse類來(lái)模擬返回信息。

接下來(lái)就開(kāi)始對(duì)UIWebView進(jìn)行離線緩存處理。

UIWebView的離線緩存處理

首先,我們需要自定義一個(gè)NSURLProtocol的子類,并且在AppDelegate.m的

 

  1. - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 
  2.     [NSURLProtocol registerClass:[ZGURLProtocol class]]; 
  3.     return YES; 

注冊(cè)。接下來(lái)的所有操作就都是在我們自定義的ZGURLProtocol中操作了。先看一下registerClass的作用:

嘗試注冊(cè)一個(gè)NSURLProtocol的子類,使其對(duì) URL Loading System 可見(jiàn)。這里的URL Loading System就是一組類和協(xié)議,允許你的應(yīng)用程序訪問(wèn)由URL產(chǎn)生的內(nèi)容,比如請(qǐng)求、接收內(nèi)容和Cache等。當(dāng)URL Load System開(kāi)始加載一個(gè)請(qǐng)求的時(shí)候,每個(gè)注冊(cè)的協(xié)議類都被依次去調(diào)用,以確定是否可以用指定的請(qǐng)求去初始化它。首先被調(diào)用的方法是:

  1. + (BOOL)canInitWithRequest:(NSURLRequest *)request; 

在該方法里面進(jìn)行緩存過(guò)濾,比如你想只緩存js,那么判斷request的path的后綴,如果是js,就返回YES,否則返回NO。

如果返回YES,那么就相當(dāng)于該請(qǐng)求被自定義的URLProtocol來(lái)處理,這里不能保證所有的注冊(cè)的NSURLProtocol都能被處理到。如果你定義了多個(gè)NSProtocol子類,這些子類將會(huì)以相反的順序調(diào)用。也就是說(shuō)如果你是這樣寫(xiě)的:

 

  1. [NSURLProtocol registerClass:[ZGURLProtocol class]];  
  2. [NSURLProtocol registerClass:[ZProtocol class]]; 

那么***執(zhí)行的是ZProtocol,如果參initWithRequest:返回的為YES,則請(qǐng)求由ZProtocol進(jìn)行處理,且不會(huì)再走ZGURLProtocol。如果ZProtocol的initWithRequest:返回的為NO,則請(qǐng)求繼續(xù)向下傳遞由其他的NSURLProtocol子類處理。

一旦返回YES,那么請(qǐng)求將會(huì)由自己寫(xiě)的子類處理,首先會(huì)調(diào)用:

  1. + (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request 

這個(gè)是一個(gè)抽象的方法,子類必須對(duì)其實(shí)現(xiàn)。通常情況下,我們一般都是直接返回request,但是這里你也可以直接修改此request,包括header,hosts等??梢詫?duì)指定request進(jìn)行重定向操作。

在這里,我們只是將現(xiàn)有的request進(jìn)行返回即可。

緊接著,便會(huì)開(kāi)始請(qǐng)求:

  1. - (void)startLoading; 

該方法的作用就是開(kāi)始請(qǐng)求protocol指定的請(qǐng)求。該方法也是protocol子類必須實(shí)現(xiàn)的方法。在這里所做的操作就是:

先判斷是否有緩存數(shù)據(jù),如果有,則自己創(chuàng)建NSURLResponse,然后將緩存數(shù)據(jù)放入,并進(jìn)行client的一些操作,然后返回;如果沒(méi)有緩存數(shù)據(jù),則新建一個(gè)NSURLConnection,然后發(fā)送請(qǐng)求。

先說(shuō)一下有緩存的情況下:

 

  1. if (model.data && model.MIMEType) { 
  2.         NSURLResponse *response = [[NSURLResponse alloc] initWithURL:self.request.URL MIMEType:model.MIMEType expectedContentLength:model.data.length textEncodingName:nil]; 
  3.         [self.client URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageAllowed]; 
  4.         [self.client URLProtocol:self didLoadData:model.data]; 
  5.         [self.client URLProtocolDidFinishLoading:self]; 
  6.         return
  7.     } 

(model是緩存數(shù)據(jù))有緩存的情況下,直接使用緩存的數(shù)據(jù)和MIME類型,然后構(gòu)建NSURLResponse,然后通過(guò)協(xié)議client調(diào)用代理方法。這里的client是一個(gè)protocol,如下:

 

  1. @protocol NSURLProtocolClient <NSObject>  
  2. - (void)URLProtocol:(NSURLProtocol *)protocol wasRedirectedToRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse; 
  3. - (void)URLProtocol:(NSURLProtocol *)protocol cachedResponseIsValid:(NSCachedURLResponse *)cachedResponse;  
  4. - (void)URLProtocol:(NSURLProtocol *)protocol didReceiveResponse:(NSURLResponse *)response cacheStoragePolicy:(NSURLCacheStoragePolicy)policy; 
  5. - (void)URLProtocol:(NSURLProtocol *)protocol didLoadData:(NSData *)data;  
  6. - (void)URLProtocolDidFinishLoading:(NSURLProtocol *)protocol;  
  7. - (void)URLProtocol:(NSURLProtocol *)protocol didFailWithError:(NSError *)error;  
  8. - (void)URLProtocol:(NSURLProtocol *)protocol didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge;  
  9. - (void)URLProtocol:(NSURLProtocol *)protocol didCancelAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge;  
  10. @end 

該協(xié)議提供了NSURLProtocol子類與URL Loading System進(jìn)行溝通的接口。一個(gè)APP一定不要去實(shí)現(xiàn)這個(gè)協(xié)議。有緩存的情況下調(diào)用回調(diào)方法,然后進(jìn)行處理。

在沒(méi)有緩存的情況下:

實(shí)例化一個(gè)connection,然后發(fā)起請(qǐng)求。在我們收到response的時(shí)候:

 

  1. - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response { 
  2.     self.responseData = [[NSMutableData alloc] init]; 
  3.     self.responseMIMEType = response.MIMEType; 
  4.     [self.client URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed]; 

緊接著就是接收數(shù)據(jù):

 

  1. - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data { 
  2.     [self.responseData appendData:data]; 
  3.     [self.client URLProtocol:self didLoadData:data]; 

接收完數(shù)據(jù)之后便調(diào)用了:

 

  1. - (void)connectionDidFinishLoading:(NSURLConnection *)connection { 
  2.     ZGCacheModel *model = [ZGCacheModel new]; 
  3.     model.data = self.responseData; 
  4.     model.MIMEType = self.responseMIMEType; 
  5.     [self setMiType:model.MIMEType withKey:[self.request.URL path]];//userdefault存儲(chǔ)MIMEtype 
  6.      
  7.      
  8.     [[ZGUIWebViewCache sharedWebViewCache] setCacheWithKey:self.request.URL.absoluteString value:model]; 
  9.    
  10.     [self.client URLProtocolDidFinishLoading:self]; 

這個(gè)方法是結(jié)束家在之后的調(diào)用,我們需要在這里將請(qǐng)求過(guò)來(lái)的數(shù)據(jù)進(jìn)行緩存。這樣我們本地就有了指定URL的返回?cái)?shù)據(jù)。

這里還有一個(gè)重要的東西沒(méi)有介紹,那就是

 

  1. [NSURLProtocol propertyForKey:ZGURLProtocolKey inRequest:request]  
  2. [NSURLProtocol setProperty:@YES forKey:ZGURLProtocolKey inRequest:mutableRequest]; 

這里的

  1. + (void)setProperty:(id)value forKey:(NSString *)key inRequest:(NSMutableURLRequest *)request; 

作用是在指定的請(qǐng)求中設(shè)置與特定的鍵值相關(guān)聯(lián)。防止多次調(diào)用一個(gè)request。

這樣,我們就完成了UIWebView的離線緩存。在這里我封裝了一個(gè) ZGUIWebViewCache 。感興趣的可以看一下。

WKWebView的離線緩存處理

WKWebView離線緩存和UIWebView緩存類似,只不過(guò)使用WKWebView除了一開(kāi)始調(diào)用一下NSURLProtocol的canInitWithRequest:方法之后,之后的請(qǐng)求似乎就和NSURLProtocol完全無(wú)關(guān)了,網(wǎng)上都說(shuō)WKWebView的請(qǐng)求是在獨(dú)立的進(jìn)程里,所以不走NSURLProtocol。這里是通過(guò)NSURLProtocol+WKWebView類進(jìn)行處理的,詳情可參見(jiàn): ZGWKWebViewCache 。

剩下的處理過(guò)程就和UIWebView緩存處理類似了。

以上便是對(duì)網(wǎng)頁(yè)離線緩存的實(shí)現(xiàn)。

責(zé)任編輯:未麗燕 來(lái)源: 張貴的站點(diǎn)
相關(guān)推薦

2017-07-15 21:10:58

CTOCEO技術(shù)

2012-03-22 10:33:33

思杰XenDesktop

2022-08-29 15:19:09

CSS煙花動(dòng)畫(huà)

2020-05-07 09:25:20

數(shù)據(jù)庫(kù)MySQL代碼

2020-02-20 19:34:24

JAVAMySQL框架

2022-09-30 15:37:19

Web網(wǎng)站服務(wù)器

2011-06-07 16:03:48

匿名SQL Server

2018-03-07 15:24:41

PythonMySQL

2009-07-06 19:29:37

云計(jì)算私有云服務(wù)器虛擬化

2017-08-24 08:31:41

2013-03-18 16:09:27

JavaEEOpenfire

2017-09-28 09:40:36

圖像分類準(zhǔn)確率

2024-07-22 11:43:28

LVMPnetLab網(wǎng)絡(luò)

2021-03-17 07:07:21

系統(tǒng)程序員SDI

2020-02-26 08:00:02

14點(diǎn)遭遇真兇

2020-10-28 15:03:25

C+代碼開(kāi)發(fā)

2019-11-04 10:06:19

MySQL索引

2010-07-12 17:10:23

Android應(yīng)用程序

2018-07-13 15:36:52

2009-12-18 16:27:43

Cisco路由器配置
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)