你好,歡迎來到IOS教程網

 Ios教程網 >> IOS編程開發 >> IOS開發基礎 >> iOS預加載Web頁面方案

iOS預加載Web頁面方案

編輯:IOS開發基礎

iOS預加載Web頁面方案

可以先下載Demo看看效果,Github地址:< GitHub - ming1016/STMURLCache: iOS預加載Web頁面方案 >
可以預加載多個網址,然後在離線狀態去顯示那幾個網址,看看是不是都完全緩存下來了。

使用方法

在需要開啟預加載的地方創建

self.sCache = [STMURLCache create:^(STMURLCacheMk *mk) {
    mk.whiteListsHost(whiteLists).whiteUserAgent(@"starming");
}];

這裡是所有可設置項目,默認設置可以查看 model 的 get 方法

- (STMURLCacheMk *(^)(NSUInteger)) memoryCapacity;   //內存容量
- (STMURLCacheMk *(^)(NSUInteger)) diskCapacity;     //本地存儲容量
- (STMURLCacheMk *(^)(NSUInteger)) cacheTime;        //緩存時間
- (STMURLCacheMk *(^)(NSString *)) subDirectory;     //子目錄
- (STMURLCacheMk *(^)(BOOL)) isDownloadMode;         //是否啟動下載模式
- (STMURLCacheMk *(^)(NSArray *)) whiteListsHost;    //域名白名單
- (STMURLCacheMk *(^)(NSString *)) whiteUserAgent;   //WebView的user-agent白名單

- (STMURLCacheMk *(^)(NSString *)) addHostWhiteList;        //添加一個域名白名單
- (STMURLCacheMk *(^)(NSString *)) addRequestUrlWhiteList;  //添加請求白名單

//NSURLProtocol相關設置
- (STMURLCacheMk *(^)(BOOL)) isUsingURLProtocol; //是否使用NSURLProtocol,默認使用NSURLCache

也可以隨時更新這些設置項

[self.sCache update:^(STMURLCacheMk *mk) {
    mk.isDownloadMode(YES);
}];

預加載名單可以按照整個 web 頁面請求進行預加載

[self.sCache preLoadByWebViewWithUrls:@[@"http://www.v2ex.com",@"http://www.github.com"];

如果需要按照單個資源列表進行預加載可以使用 preLoadByRequestWithUrls 這個方法。

白名單設置

對於只希望緩存特定域名或者地址的可以通過白名單進行設置,可以在創建時進行設置或者更新時設置。

NSString *whiteListStr = @"www.starming.com|www.github.com|www.v2ex.com|www.baidu.com";
NSMutableArray *whiteLists = [NSMutableArray arrayWithArray:[whiteListStr componentsSeparatedByString:@"|"]];
self.sCache = [STMURLCache create:^(STMURLCacheMk *mk) {
    mk.whiteListsHost(whiteLists).whiteUserAgent(@"starming");
}];

這裡的 whiteUserAgent 的設置會設置 webview 的 UserAgent,這樣能夠讓webview以外的網絡請求被過濾掉。

基本加載緩存實現原理

創建 STMURLCache 後設置 NSURLCacheURLCache ,在 cachedResponseForRequest 方法中獲取 NSURLRequest 判斷白名單,檢驗是否有與之對應的 Cache ,有就使用本地數據返回 NSCachedURLResponse ,沒有就通過網絡獲取數據數據緩存。 STMURLCache 對象釋放時將 NSURLCache 設置為不緩存,表示這次預加載完成不需要再緩存。當緩存空間超出設置大小會將其清空。

使用 NSURLProtocol 這種原理基本類似。

白名單實現原理

創建域名列表設置項 whiteListsHostuserAgent 設置項,在創建和更新時對其進行設置。在網絡請求開始通過設置項進行過濾。具體實現如下

//對於域名白名單的過濾
if (self.mk.cModel.whiteListsHost.count > 0) {
    id isExist = [self.mk.cModel.whiteListsHost objectForKey:[self hostFromRequest:request]];
    if (!isExist) {
        return nil;
    }
}
//User-Agent來過濾
if (self.mk.cModel.whiteUserAgent.length > 0) {
    NSString *uAgent = [request.allHTTPHeaderFields objectForKey:@"User-Agent"];
    if (uAgent) {
        if (![uAgent hasSuffix:self.mk.cModel.whiteUserAgent]) {
            return nil;
        }
    }
}

具體緩存實現

緩存的實現有兩種,一種是 NSURLCache 另一種是 NSURLProtocolSTMURLCache 同時支持了這兩種,通過 STMURLCacheModel 裡的 isUsingURLProtocol 設置項來選擇使用哪個。

NSURLCache的實現

沒有緩存的 request 會對其進行請求將獲取數據按照hash地址存兩份於本地,一份是數據,一份記錄時間和類型,時間記錄可以用於判斷失效時間。對於判斷是否有緩存可以根據請求地址對應的文件進行判斷。具體實現如下:

- (NSCachedURLResponse *)localCacheResponeWithRequest:(NSURLRequest *)request {
    __block NSCachedURLResponse *cachedResponse = nil;
    NSString *filePath = [self filePathFromRequest:request isInfo:NO];
    NSString *otherInfoPath = [self filePathFromRequest:request isInfo:YES];
    NSDate *date = [NSDate date];
    NSFileManager *fm = [NSFileManager defaultManager];
    if ([fm fileExistsAtPath:filePath]) {
        //有緩存文件的情況
        BOOL expire = false;
        NSDictionary *otherInfo = [NSDictionary dictionaryWithContentsOfFile:otherInfoPath];
        if (self.cacheTime > 0) {
            NSInteger createTime = [[otherInfo objectForKey:@"time"] integerValue];
            if (createTime + self.cacheTime < [date timeIntervalSince1970]) {
                expire = true;
            }
        }
        if (expire == false) {
            //從緩存裡讀取數據
            NSData *data = [NSData dataWithContentsOfFile:filePath];
            NSURLResponse *response = [[NSURLResponse alloc] initWithURL:request.URL MIMEType:[otherInfo objectForKey:@"MIMEType"] expectedContentLength:data.length textEncodingName:[otherInfo objectForKey:@"textEncodingName"]];
            NSCachedURLResponse *cachedResponse = [[NSCachedURLResponse alloc] initWithResponse:response data:data];
            return cachedResponse;
        } else {
            //cache失效了
            [fm removeItemAtPath:filePath error:nil];      //清除緩存data
            [fm removeItemAtPath:otherInfoPath error:nil]; //清除緩存其它信息
            return nil;
        }
    } else {
        //從網絡讀取
        self.isSavedOnDisk = NO;
        id isExist = [self.responseDic objectForKey:request.URL.absoluteString];
        if (isExist == nil) {
            [self.responseDic setValue:[NSNumber numberWithBool:TRUE] forKey:request.URL.absoluteString];
            NSURLSession *session = [NSURLSession sharedSession];
            NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
                if (error) {
                    cachedResponse = nil;
                } else {
                    NSDictionary *dic = [NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@"%f",[date timeIntervalSince1970]],@"time",response.MIMEType,@"MIMEType",response.textEncodingName,@"textEncodingName", nil];
                    BOOL resultO = [dic writeToFile:otherInfoPath atomically:YES];
                    BOOL result = [data writeToFile:filePath atomically:YES];
                    if (resultO == NO || result == NO) {
                    } else {
                    }
                    cachedResponse = [[NSCachedURLResponse alloc] initWithResponse:response data:data];
                }
            }];
            [task resume];
            return cachedResponse;
        }
        return nil;
    }
}

NSURLProtocol的實現

在設置配置項和更新配置項時需要創建一個 STMURLCacheModel 的單例來進行設置和更新配置項給 NSURLProtocol 的實現來使用。通過 isUsingURLProtocol 設置項區分, NSURLProtocol 是通過registerClass方式將protocol實現的進行注冊。

- (STMURLCache *)configWithMk {

    self.mk.cModel.isSavedOnDisk = YES;

    if (self.mk.cModel.isUsingURLProtocol) {
        STMURLCacheModel *sModel = [STMURLCacheModel shareInstance];
        sModel.cacheTime = self.mk.cModel.cacheTime;
        sModel.diskCapacity = self.mk.cModel.diskCapacity;
        sModel.diskPath = self.mk.cModel.diskPath;
        sModel.cacheFolder = self.mk.cModel.cacheFolder;
        sModel.subDirectory = self.mk.cModel.subDirectory;
        sModel.whiteUserAgent = self.mk.cModel.whiteUserAgent;
        sModel.whiteListsHost = self.mk.cModel.whiteListsHost;
        [NSURLProtocol registerClass:[STMURLProtocol class]];
    } else {
        [NSURLCache setSharedURLCache:self];
    }
    return self;
}

關閉時兩者也是不同的,通過設置項進行區分

- (void)stop {
    if (self.mk.cModel.isUsingURLProtocol) {
        [NSURLProtocol unregisterClass:[STMURLProtocol class]];
    } else {
        NSURLCache *c = [[NSURLCache alloc] initWithMemoryCapacity:0 diskCapacity:0 diskPath:nil];
        [NSURLCache setSharedURLCache:c];
    }
    [self.mk.cModel checkCapacity];
}

白名單處理還有讀取緩存和前者都類似,但是在緩存Data時 NSURLCached 的方案裡是通過發起一次新的請求來獲取數據,而 NSURLProtocolNSURLConnection 的 Delegate 裡可以獲取到,少了一次網絡的請求,這裡需要注意的是在 - (void) connection:(NSURLConnection )connection didReceiveData:(NSData )data 每次從這個回調裡獲取的數據不是完整的,要在 - (void) connectionDidFinishLoading:(NSURLConnection *)connection 這個會調裡將分段數據拼接成完整的數據保存下來。具體完整的代碼實現可以看 STMURLProtocol 裡的代碼實現。

後記

通過 map 網絡請求可以緩存請求,也可以 mock 接口請求進行測試。

完整代碼:< GitHub - ming1016/STMURLCache: iOS預加載Web頁面方案 >





  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved