1. 程式人生 > >WebView離線快取開發

WebView離線快取開發


因為公司一個以H5為主要核心的專案,進行了了大量的調研尋找合適的iOS網頁離線快取檢視,最後敲定使用基於NSURLCache框架開發這個功能。專案完畢,因為在網上沒有找到響應需求的良好開源庫,在網上找到一個基於NSURLCache開發的專案,因為並不完整,就利用休整時間借鑑原專案的經驗開發了一個實現網頁離線瀏覽的開源庫(DPWebViewLocalCache)。

一、上圖片,看效果

二、上程式碼,Demo程式碼實現

實現程式碼:

//

//  DPLocalCache.h

//  DPLocalCache

//

//  Created by yupeng xia on 2016/11/10.

//  Copyright © 2016 yupeng xia. All rights reserved.

//


#import <Foundation/Foundation.h>

#import "Reachability.h"

#import "DPLocalCacheTool.h"


typedef enum : NSUInteger{

    NORMAL_MODE = 0,   

//系統的快取 (ustomCacheNSURLCache的功能是一樣的)

    DOWNLOAD_MODE = 1  //自定義快取 (CustomURLCache則可以實現包含自定義下載目錄,設定過期時間的子功能的下載功能)

}MODE_TYPE;

@interface DPLocalCache : NSURLCache

@property(nonatomic,assign)NSInteger cacheTime;      //新增快取間隔時間

@property(nonatomic,strong

)NSString *diskPath;       //沙盒路徑

@property(nonatomic,strong)NSString *subDirectory;   //子路徑

@property(nonatomic,assign)MODE_TYPE aMode;          //快取型別

@property(nonatomic,strong)NSMutableDictionary *responseDictionary;  //響應的字典

@property(nonatomic,strong)NSMutableDictionary *localReourcePath;    //手動新增本地快取

@property(nonatomic,strong)NSArray *keyArray;   //URL需要刪除的鍵值對(某些鍵值對會改變,因此需要刪除)


///初始快取儲存本地空間

- (id)initWithMemoryCapacity:(NSUInteger)memoryCapacity diskCapacity:(NSUInteger)diskCapacity diskPath:(NSString *)path cacheTime:(NSInteger)cacheTime modeTybe:(MODE_TYPE)aModeTybe subDirectory:(NSString*)subDirectory;

///刪除快取資料夾

- (void)deleteCacheFolder;

@end


//

//  DPLocalCache.m

//  DPLocalCache

//

//  Created by yupeng xia on 2016/11/10.

//  Copyright © 2016 yupeng xia. All rights reserved.

//


#import "DPLocalCache.h"


@implementation DPLocalCache

- (id)initWithMemoryCapacity:(NSUInteger)aMemoryCapacity diskCapacity:(NSUInteger)aDiskCapacity diskPath:(NSString *)aDiskPath cacheTime:(NSInteger)aCacheTime modeTybe:(MODE_TYPE)aModeTybe subDirectory:(NSString*)aSubDirectory{

    if (self = [selfinitWithMemoryCapacity:aMemoryCapacitydiskCapacity:aDiskCapacitydiskPath:aDiskPath]) {

        if (aDiskPath){

            self.diskPath = aDiskPath;

        }else{

            self.diskPath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory,NSUserDomainMask,YES)lastObject];

        }

        NSLog(@"Local cache disk path: %@",self.diskPath);

        

        self.cacheTime = aCacheTime;

        self.aMode = aModeTybe;

        self.subDirectory = aSubDirectory;

        

        self.responseDictionary = [NSMutableDictionarydictionaryWithCapacity:0];

        //手動新增本地快取

        self.localReourcePath = [NSMutableDictionarydictionaryWithCapacity:0];

    }

    return self;

}


#pragma mark <----------重寫NSURLCache函式---------->

#pragma mark 快取的響應請求 (如果對應的NSURLRequest沒有cachedresponse那麼返回nil)

- (NSCachedURLResponse *)cachedResponseForRequest:(NSURLRequest *)request{

    NSString *url = request.URL.absoluteString;

    //    NSLog(@"normal mode:%@",[[request URL]absoluteString]);

    //    NSLog(@"data from request %@",[request description]);

    

    if (_aMode ==NORMAL_MODE) {//使用系統快取型別

        return [supercachedResponseForRequest:request];

    }

    

    if ([request.HTTPMethodcompare:@"GET"] !=NSOrderedSame) {//不處理非get請求

        return [supercachedResponseForRequest:request];

    }

    

    if ([self.localReourcePathobjectForKeyedSubscript:url] !=nil) {//手動新增本地快取不為空

        NSCachedURLResponse *cachedResponse = [selfloadLocalResouce:requestpath:[self.localReourcePathobjectForKey:url]];

        if (cachedResponse !=nil) {//新增成功

            return cachedResponse;

        }else {//新增失敗

            return [selfdataFromRequest:request];

        }

    }

    return  [selfdataFromRequest:request];

}

/*

 *網路請求本地快取處理

 *沒有網路使用本地快取;

 *有網路使新增本地快取;

 */

- (NSCachedURLResponse *)dataFromRequest:(NSURLRequest *)request{

    NSString *url = request.URL.absoluteString;

    

    //sessionId(不斷改變,載入本地快取,需要刪除當前欄位)

    for (NSString *keyStrin_keyArray) {

        NSRange range;

        range = [url rangeOfString:keyStr];

        if (range.location !=NSNotFound) {

            //使用者為登陸,去除已經拼接的sessionId

            url = [NSMutableStringstringWithFormat:@"%@",[DPLocalCacheToolurlDeleteValueOfParam:urlwithParam:keyStr]];

        }

    }

    

    //當前資源的本地儲存子目錄的檔名

    NSString *fileName = [selfcacheRequestFileName:url];

    //當前資源描述檔案的本地儲存子目錄的檔名

    NSString *otherInfoFileName = [selfcacheRequestDescriptionFileName:url];

    //當前資源的本地儲存路徑

    NSString *filePath = [selfcacheFilePath:fileName];

    //當前資源描述檔案的本地儲存路徑

    NSString *otherInfoPath = [selfcacheFilePath:otherInfoFileName];

    

    NSDate *date = [NSDatedate];

    NSFileManager *fileManager = [NSFileManagerdefaultManager];

    

    //獲取網路狀態

    Reachability *reachability = [ReachabilityreachabilityForInternetConnection];

    NetworkStatus internetStatus = [reachabilitycurrentReachabilityStatus];

    if (internetStatus ==NotReachable) {//網路不可用,使用本地快取

        if ([fileManagerfileExistsAtPath:filePath]) {

            NSDictionary *otherInfo = [NSDictionarydictionaryWithContentsOfFile:otherInfoPath];

            

            NSData *data = [NSDatadataWithContentsOfFile:filePath];

            NSURLResponse *response = [[NSURLResponsealloc]initWithURL:request.URL

                                                                MIMEType:[otherInfo objectForKey:@"MIMEType"]

                                                   expectedContentLength:data.length

                                                        textEncodingName:[otherInfoobjectForKey:@"textEncodingName"]];

            NSCachedURLResponse *cachedResponse = [[NSCachedURLResponsealloc]initWithResponse:responsedata:data];

            return cachedResponse;

        }

        

    }else{//網路可用,相對應的網頁本地快取不存在,儲存本地快取

        BOOL expire = false;

        NSDictionary *otherInfo = [NSDictionarydictionaryWithContentsOfFile:otherInfoPath];

        

        if (self.cacheTime >0) {

            NSInteger createTime = [[otherInfoobjectForKey:@"time"]intValue];

            if(createTime){

                if (createTime +self.cacheTime > [datetimeIntervalSince1970]) {

                    expire = true;

                }

            }

        }

        

        if (expire == false) {//快取到期,重新下載快取資料

            id boolExsite = [_responseDictionaryobjectForKey:url];

            if (boolExsite ==nil) {

                [self.responseDictionarysetValue:[NSNumbernumberWithBool:TRUE]forKey:url];

                

                __blockNSCachedURLResponse *cachedResponse =nil;

                

                [NSURLConnectionsendAsynchronousRequest:requestqueue:[[NSOperationQueuealloc]init]completionHandler:^(NSURLResponse *response,NSData *data,NSError *error) {

                    //NSLog(@"下載資源結束返回地址: %@", request.URL.absoluteString);

                    

                    if (response && date) {

                        if (error) {

                            NSLog(@"error : %@", error);

                            cachedResponse = nil;

                        }else {

                            //生成快取資源的描述檔案

                            NSDictionary *dict = [NSDictionarydictionaryWithObjectsAndKeys:[NSStringstringWithFormat:@"%f", [datetimeIntervalSince1970]], @"time", response.MIMEType,@"MIMEType", response.textEncodingName,@"textEncodingName",nil];

                            //快取資源的描述檔案存入本地

                            BOOL otherInfoResult = [dictwriteToFile:otherInfoPathatomically:YES];

                            //快取資源存入本地

                            BOOL result = [datawriteToFile:filePathatomically:YES];

                            if(otherInfoResult ==NO || result ==NO) {

                                NSLog(@"寫入錯誤,路徑:%@",filePath);

                            }else {

                                NSLog(@"寫入成功,路徑:%@",filePath);

                            }

                            cachedResponse = [[NSCachedURLResponsealloc]initWithResponse:responsedata:data];

                            

                        }

                    }

                }];

                [superstoreCachedResponse:cachedResponseforRequest:request];

                return cachedResponse;

            }

        }

        

        

        

    }

    return nil;

}

//手動新增本地快取處理,輸出快取內容

- (NSCachedURLResponse*)loadLocalResouce:(NSURLRequest*)request path:(NSString*)path{

    //NSLog(@"load from local source %@,%@",request.URL.absoluteString,path);

    NSFileManager* fileManager = [NSFileManagerdefaultManager];

    if (![fileManager fileExistsAtPath:path]) {

        return nil;

    }

    

    // Load the data

    NSData *data = [NSDatadataWithContentsOfFile:path];

    

    // Create the cacheable response

    NSURLResponse *response = [[NSURLResponsealloc]

                               initWithURL:[requestURL]

                               MIMEType:[selfmimeTypeForPath:[[requestURL]absoluteString]]

                               expectedContentLength:[datalength]

                               textEncodingName:nil];

    

    NSCachedURLResponse *cachedResponse = [[NSCachedURLResponsealloc]initWithResponse:responsedata:data];

    [self storeCachedResponse:cachedResponseforRequest:request];

    return cachedResponse;

}


#pragma mark 移除特定NSURLRequestcache

- (void)removeCachedResponseForRequest:(NSURLRequest *)request{

    [super removeCachedResponseForRequest:request];

    //這句要不要需要測試一下

    NSString *url = request.URL.absoluteString;

    NSString *fileName = [selfcacheRequestFileName:url];

    NSString *otherInfoFileName = [selfcacheRequestDescriptionFileName:url];

    NSString *filePath = [selfcacheFilePath:fileName];

    NSString *otherInfoPath = [selfcacheFilePath:otherInfoFileName];

    NSFileManager *fileManager = [NSFileManagerdefaultManager];

    [fileManager removeItemAtPath:filePatherror:nil];

    [fileManager removeItemAtPath:otherInfoPatherror:nil];

}


#pragma mark 移除所有的cache

- (void)removeAllCachedResponses{

    [super removeAllCachedResponses];

}


#pragma mark <----------快取使用過程中的處理---------->

#pragma mark 獲取檔案路徑_file:檔名稱

- (NSString *)cacheFilePath:(NSString *)file{

    NSString *path = [NSStringstringWithFormat:@"%@/%@",self.diskPath, [selfcacheFolder]];

    NSFileManager *fileManager = [NSFileManagerdefaultManager];

    BOOL isDir;

    if ([fileManager fileExistsAtPath:path isDirectory:&isDir] && isDir) {

        

    }else {

        [fileManager createDirectoryAtPath:pathwithIntermediateDirectories:YESattributes:nilerror:nil];

    }

    

    NSString *subDirPath = [NSStringstringWithFormat:@"%@/%@/%@",self.diskPath,[selfcacheFolder],self.subDirectory];

    if ([fileManager fileExistsAtPath:subDirPath isDirectory:&isDir] && isDir) {

        

    }else {

        [fileManager createDirectoryAtPath:subDirPathwithIntermediateDirectories:YESattributes:nilerror:nil];

    }

    //    NSLog(@"快取本地儲存路徑: %@",[NSString stringWithFormat:@"%@/%@", subDirPath, file]);

    return [NSStringstringWithFormat:@"%@/%@", subDirPath, file];

}


#pragma mark 刪除快取資料夾

- (void)deleteCacheFolder{

    NSString *path = [NSStringstringWithFormat:@"%@/%@/%@",self.diskPath, [selfcacheFolder],_subDirectory];

    NSLog(@"delete file:%@",path);

    NSFileManager *fileManager = [NSFileManagerdefaultManager];

    [fileManager removeItemAtPath:patherror:nil];

}

#pragma mark 根據當前資源的網址,生成當前資源的本地儲存子目錄的檔名

- (NSString *)cacheRequestFileName:(NSString *)requestUrl{

    //子目錄名字轉義

    NSString *subPath = [DPLocalCacheToolmd5Hash:[DPLocalCacheToolmd5Hash:requestUrl]];

    //獲得檔案的字尾名(不帶'.'

    NSString *exestr = [requestUrlpathExtension];

    if (exestr.length >0) {

        //處理檔案,根據相對應的格式生成相對應檔名稱

        subPath = [NSStringstringWithFormat:@"%@.%@",subPath,exestr];

    }

    //    NSLog(@"資源_子目錄:%@",subPath);

    return subPath;

}

#pragma mark 根據當前資源的網址,生成當前資源描述檔案的本地儲存子目錄的檔名

- (NSString *)cacheRequestDescriptionFileName:(NSString *)requestUrl{

    NSString *subPath = [DPLocalCacheToolmd5Hash:[NSStringstringWithFormat:@"%@-otherInfo", requestUrl]];

    //    NSLog(@"資源_描述檔案_子目錄:%@",subPath);

    return subPath;

}

#pragma mark 自定義快取_本地儲存資料夾

- (NSString *)cacheFolder{

    return @"URLCACHE";

}

#pragma mark 當前程式碼只有替代品PNG影象

- (NSString *)mimeTypeForPath:(NSString *)originalPath{

    return @"image/png";

}


- (void)setKeyArray:(NSArray *)keyArray{

    _keyArray = keyArray;

}

@end


使用程式碼:

//

//  ViewController.h

//  DPWebViewLocalCacheDemo

//

//  Created by yupeng xia on 2016/11/11.

//  Copyright © 2016 yupeng xia. All rights reserved.

//


#import <UIKit/UIKit.h>


@interface ViewController : UIViewController


@property (weak,nonatomic)IBOutletUIWebView *myWebView;


@end



//

//  ViewController.m

//  DPWebViewLocalCacheDemo

//

//  Created by yupeng xia on 2016/11/11.

//  Copyright © 2016 yupeng xia. All rights reserved.

//


#import "ViewController.h"

#import "DPLocalCache.h"


@interface ViewController ()<UIWebViewDelegate>{


}

//網路請求活動指示器

@property(nonatomic,strong)UIActivityIndicatorView* activityIndicatorView;

@end


@implementation ViewController

#pragma mark <----------View LifeCycle---------->

- (void)viewWillDisappear:(BOOL)animated{

    [super viewWillDisappear:animated];

}

- (void)viewWillAppear:(BOOL)animated{

    [super viewWillAppear:animated];

}

- (void)viewDidAppear:(BOOL)animated{

    [super viewDidAppear:animated];

相關推薦

WebView離線快取開發

因為公司一個以H5為主要核心的專案,進行了了大量的調研尋找合適的iOS網頁離線快取檢視,最後敲定使用基於NSURLCache框架開發這個功能。專案完畢,因為在網上沒有找到響應需求的良好開源庫,在網上找到一個基於NSURLCache開發的專案,因為並不完整,就利用休整時間借鑑原專案的經驗開發

iOS開發 最新的NSURLProtocol之webView離線快取快取webView離線載入

四:1.+ (BOOL)canInitWithRequest:(NSURLRequest *)request; 作用:(1).處理返回YES,不處理返回NO (2).打標籤,已經處理過的不在處理 這篇文章有具體說明:http://www.jianshu.com/p/7c89b8c5482a 2.+ (NSU

Android之 -WebView實現離線快取閱讀

前言 本篇部落格要實現的是一個離線下載和離線閱讀的功能,這是很多閱讀類app都常見的一個功能,典型的應用就是網易新聞。什麼是離線下載?其實這個概念是比較模糊,是離線之後下載呢,還是下載之後離線,但稍微有點腦子的人都知道沒有網路之後怎麼下載呢?所以離線下載這個功能是”在有網路的情況下,把資源下載到本地“,離線

iOS開發本地快取(資料離線快取、讀取、釋放)

1、設定全域性的Cache     在AppDelegate.h中新增一個全域性變數 @interface AppDelegate : UIResponder    {       ASIDownloadCache *myCache;   }   @property (strong, nonat

springboot快取開發

前言:快取在開發中是一個必不可少的優化點,近期在公司的專案重構中,關於快取優化了很多點,比如在載入一些資料比較多的場景中,會大量使用快取機制提高介面響應速度,簡介提升使用者體驗。關於快取,很多人對它都是既愛又恨,愛它的是:它能大幅提升響應效率,恨的是它如果處理不好,沒有用好比如LRU這種策略,沒有及

springboot快取開發實戰

前言: 快取在開發中是一個必不可少的優化點,近期在公司的專案重構中,關於快取優化了很多點,比如在載入一些資料比較多的場景中,會大量使用快取機制提高介面響應速度,簡介提升使用者體驗。關於快取,很多人對它都是既愛又恨,愛它的是:它能大幅提升響應效率,恨的是它如果處理不好,沒有用好比如LRU這種策略,

html5 manifest 離線快取

轉於:https://blog.csdn.net/lijc_boke/article/details/69666021 版權宣告:隨便看,歡迎技術交流,523252797(qq) https://blog.csdn.net/lijc_boke/article/details/69666021

H5離線快取技術Application Cache

H5離線快取技術Application Cache 1、離線快取技術:是瀏覽器本身的一種機制 HTML5引入Application Cache(應用程式快取)技術,離線儲存可以將站點的一些檔案儲存在本地,在沒有網路的情況下可以訪問到已快取的對應的站點頁面,這些檔案包括html、js、css、img等檔案;

離線快取manifest、獲取經緯度、獲取地圖

一.離線快取manifest作用:伺服器開啟執行一次後,斷開伺服器也能顯示資訊1.建立demo.manifest檔案編輯的內容如下,放在同級目錄或則其他可訪問的位置即可程式碼: CACHE MANIFEST #v1.0.0 CACHE: img/1.png demo14.html 2

資料庫離線快取展示資料專項練習(一)

資料庫離線快取展示資料專項練習 View view = inflater.inflate(R.layout.fragment2, container, false); listView = view.findViewById(R.id.listview); MyHelper helper

H5應用離線快取

使用 HTML5,通過建立 cache manifest 檔案,可以輕鬆地建立 web 應用的離線版本。 HTML5 引入了應用程式快取,這意味著 web 應用可進行快取,並可在沒有因特網連線時進行訪問。 應用程式快取為應用帶來三個優勢: 離線瀏覽 - 使用者可在應用離

FBO和FBOA離線快取物件方便高效實現累積快取功能

FBO是不使用視窗系統提供的顏色前後臺快取和輔助快取,深度快取,模板快取。 而是在OGL層面在GPU中開闢這些快取,這些快取有兩種型別,TextureBuffer(存放紋理顏色快取), RenderFrameBuffer(存放深度和模板快取,也可以存放顏色快取), 這些快

【前端】離線快取

1、HTML5離線快取 離線快取是Html5新特性之一,簡單理解就是第一次載入後將資料快取,在沒有清除快取前提下,下一次沒有網路也可以載入,用在靜態資料的網頁或遊戲比較好用。 使用方式: (1)引入manifest檔案。 <!DOCTYPE html> <

iOS資料庫離線快取思路和網路層封裝——原理

資料展示型的頁面做離線快取可以有更好的使用者體驗,使用者在離線環境下,或是網路載入異常的情況下,仍然可以獲取一些已經快取的資料進行頁面的顯示,以避免頁面空白。 進行資料快取操作,首選SQLite+FM

HTML5新特性之離線快取技術實戰

八、離線Web應用實戰。 通過一個簡單的記事本程式——PermaNote,來解釋如何使用。程式將使用者的文字儲存到localStorage中,並且在網路連線可用的時候, 將其上傳到伺服器,PermaNote只允許使用者編輯單個筆記。 PermaNote應用包含3個檔案,一個應用清單檔案、

iOS資料庫離線快取思路和網路層封裝

關於XLNetworkApi XLNetworkApi的一些功能和說明: 使用XLNetworkRequest做一些GET、POST、PUT、DELETE請求,與業務邏輯對接部分直接以陣列或者字典的形式返回。以及網路下載、上傳檔案,以block的形式返回實時的下載、上傳進度,上傳檔案引數通過模型XLFi

HTML5 離線快取DEMO示例

1.index.manifest檔案配置 CACHE MANIFEST #chrome瀏覽器支援,火狐瀏覽器支援度不夠好 #version 1 #author by guoquanyou #CACHE:其後列出的是需要快取的內容 CACHE: index.html cs

使用NSURLProtocol實現離線快取

一、說明:NSURLProtocol可以攔截任何網路請求,包含UIWebView中發出的所有請求。但是在WKWebView中,只能攔截到最初始的請求,內嵌的資源下載攔截不到。比如通過WKWebView載

離線快取

前言:本篇介紹Android中的各種快取機制和快取框架,同樣借鑑網上的一些知識總結分享給大家。HR經常問到的快取機制?客戶端快取機制是android應用開發中非常重要的一項工作了,使用快取機制不僅可以為客戶節省流量,同時提高了使用者體驗,比如今日頭條的離線模式,就是通過快取機

Spring Boot + Mybatis + Redis二級快取開發指南

背景Spring-Boot因其提供了各種開箱即用的外掛,使得它成為了當今最為主流的Java Web開發框架之一。Mybatis是一個十分輕量好用的ORM框架。Redis是當今十分主流的分散式key-value型資料庫,在web開發中,我們常用它來快取資料庫的查詢結果。本篇部落