技术控

    今日:68| 主题:49270
收藏本版 (1)
最新软件应用技术尽在掌握

[其他] iOS预加载Web页面方案

[复制链接]
努力微笑 发表于 6 天前
82 0

立即注册CoLaBug.com会员,免费获得投稿人的专业资料,享用更多功能,玩转个人品牌!

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
iOS预加载Web页面方案

    可以先下载Demo看看效果,Github地址:<      GitHub - ming1016/STMURLCache: iOS预加载Web页面方案>   
    可以预加载多个网址,然后在离线状态去显示那几个网址,看看是不是都完全缓存下来了。
    使用方法

  在需要开启预加载的地方创建
  1. self.sCache = [STMURLCache create:^(STMURLCacheMk *mk) {
  2.     mk.whiteListsHost(whiteLists).whiteUserAgent(@"starming");
  3. }];
复制代码
这里是所有可设置项目,默认设置可以查看 model 的 get 方法
  1. - (STMURLCacheMk *(^)(NSUInteger)) memoryCapacity;   //内存容量
  2. - (STMURLCacheMk *(^)(NSUInteger)) diskCapacity;     //本地存储容量
  3. - (STMURLCacheMk *(^)(NSUInteger)) cacheTime;        //缓存时间
  4. - (STMURLCacheMk *(^)(NSString *)) subDirectory;     //子目录
  5. - (STMURLCacheMk *(^)(BOOL)) isDownloadMode;         //是否启动下载模式
  6. - (STMURLCacheMk *(^)(NSArray *)) whiteListsHost;    //域名白名单
  7. - (STMURLCacheMk *(^)(NSString *)) whiteUserAgent;   //WebView的user-agent白名单
  8. - (STMURLCacheMk *(^)(NSString *)) addHostWhiteList;        //添加一个域名白名单
  9. - (STMURLCacheMk *(^)(NSString *)) addRequestUrlWhiteList;  //添加请求白名单
  10. //NSURLProtocol相关设置
  11. - (STMURLCacheMk *(^)(BOOL)) isUsingURLProtocol; //是否使用NSURLProtocol,默认使用NSURLCache
复制代码
也可以随时更新这些设置项
  1. [self.sCache update:^(STMURLCacheMk *mk) {
  2.     mk.isDownloadMode(YES);
  3. }];
复制代码
预加载名单可以按照整个 web 页面请求进行预加载
  1. [self.sCache preLoadByWebViewWithUrls:@[@"http://www.v2ex.com",@"http://www.github.com"];
复制代码
如果需要按照单个资源列表进行预加载可以使用    preLoadByRequestWithUrls这个方法。  
  白名单设置

  对于只希望缓存特定域名或者地址的可以通过白名单进行设置,可以在创建时进行设置或者更新时设置。
  1. NSString *whiteListStr = @"www.starming.com|www.github.com|www.v2ex.com|www.baidu.com";
  2. NSMutableArray *whiteLists = [NSMutableArray arrayWithArray:[whiteListStr componentsSeparatedByString:@"|"]];
  3. self.sCache = [STMURLCache create:^(STMURLCacheMk *mk) {
  4.     mk.whiteListsHost(whiteLists).whiteUserAgent(@"starming");
  5. }];
复制代码
这里的    whiteUserAgent的设置会设置 webview 的 UserAgent,这样能够让webview以外的网络请求被过滤掉。  
  基本加载缓存实现原理

  创建    STMURLCache后设置    NSURLCache的    URLCache,在    cachedResponseForRequest方法中获取    NSURLRequest判断白名单,检验是否有与之对应的 Cache ,有就使用本地数据返回    NSCachedURLResponse,没有就通过网络获取数据数据缓存。    STMURLCache对象释放时将    NSURLCache设置为不缓存,表示这次预加载完成不需要再缓存。当缓存空间超出设置大小会将其清空。  
  使用    NSURLProtocol这种原理基本类似。  
  白名单实现原理

  创建域名列表设置项    whiteListsHost和    userAgent设置项,在创建和更新时对其进行设置。在网络请求开始通过设置项进行过滤。具体实现如下  
  1. //对于域名白名单的过滤
  2. if (self.mk.cModel.whiteListsHost.count > 0) {
  3.     id isExist = [self.mk.cModel.whiteListsHost objectForKey:[self hostFromRequest:request]];
  4.     if (!isExist) {
  5.         return nil;
  6.     }
  7. }
  8. //User-Agent来过滤
  9. if (self.mk.cModel.whiteUserAgent.length > 0) {
  10.     NSString *uAgent = [request.allHTTPHeaderFields objectForKey:@"User-Agent"];
  11.     if (uAgent) {
  12.         if (![uAgent hasSuffix:self.mk.cModel.whiteUserAgent]) {
  13.             return nil;
  14.         }
  15.     }
  16. }
复制代码
具体缓存实现

  缓存的实现有两种,一种是    NSURLCache另一种是    NSURLProtocol,    STMURLCache同时支持了这两种,通过    STMURLCacheModel里的    isUsingURLProtocol设置项来选择使用哪个。  
  NSURLCache的实现

  没有缓存的 request 会对其进行请求将获取数据按照hash地址存两份于本地,一份是数据,一份记录时间和类型,时间记录可以用于判断失效时间。对于判断是否有缓存可以根据请求地址对应的文件进行判断。具体实现如下:
  1. - (NSCachedURLResponse *)localCacheResponeWithRequest:(NSURLRequest *)request {
  2.     __block NSCachedURLResponse *cachedResponse = nil;
  3.     NSString *filePath = [self filePathFromRequest:request isInfo:NO];
  4.     NSString *otherInfoPath = [self filePathFromRequest:request isInfo:YES];
  5.     NSDate *date = [NSDate date];
  6.     NSFileManager *fm = [NSFileManager defaultManager];
  7.     if ([fm fileExistsAtPath:filePath]) {
  8.         //有缓存文件的情况
  9.         BOOL expire = false;
  10.         NSDictionary *otherInfo = [NSDictionary dictionaryWithContentsOfFile:otherInfoPath];
  11.         if (self.cacheTime > 0) {
  12.             NSInteger createTime = [[otherInfo objectForKey:@"time"] integerValue];
  13.             if (createTime + self.cacheTime < [date timeIntervalSince1970]) {
  14.                 expire = true;
  15.             }
  16.         }
  17.         if (expire == false) {
  18.             //从缓存里读取数据
  19.             NSData *data = [NSData dataWithContentsOfFile:filePath];
  20.             NSURLResponse *response = [[NSURLResponse alloc] initWithURL:request.URL MIMEType:[otherInfo objectForKey:@"MIMEType"] expectedContentLength:data.length textEncodingName:[otherInfo objectForKey:@"textEncodingName"]];
  21.             NSCachedURLResponse *cachedResponse = [[NSCachedURLResponse alloc] initWithResponse:response data:data];
  22.             return cachedResponse;
  23.         } else {
  24.             //cache失效了
  25.             [fm removeItemAtPath:filePath error:nil];      //清除缓存data
  26.             [fm removeItemAtPath:otherInfoPath error:nil]; //清除缓存其它信息
  27.             return nil;
  28.         }
  29.     } else {
  30.         //从网络读取
  31.         self.isSavedOnDisk = NO;
  32.         id isExist = [self.responseDic objectForKey:request.URL.absoluteString];
  33.         if (isExist == nil) {
  34.             [self.responseDic setValue:[NSNumber numberWithBool:TRUE] forKey:request.URL.absoluteString];
  35.             NSURLSession *session = [NSURLSession sharedSession];
  36.             NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
  37.                 if (error) {
  38.                     cachedResponse = nil;
  39.                 } else {
  40.                     NSDictionary *dic = [NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@"%f",[date timeIntervalSince1970]],@"time",response.MIMEType,@"MIMEType",response.textEncodingName,@"textEncodingName", nil];
  41.                     BOOL resultO = [dic writeToFile:otherInfoPath atomically:YES];
  42.                     BOOL result = [data writeToFile:filePath atomically:YES];
  43.                     if (resultO == NO || result == NO) {
  44.                     } else {
  45.                     }
  46.                     cachedResponse = [[NSCachedURLResponse alloc] initWithResponse:response data:data];
  47.                 }
  48.             }];
  49.             [task resume];
  50.             return cachedResponse;
  51.         }
  52.         return nil;
  53.     }
  54. }
复制代码
NSURLProtocol的实现

  在设置配置项和更新配置项时需要创建一个    STMURLCacheModel的单例来进行设置和更新配置项给 NSURLProtocol 的实现来使用。通过 isUsingURLProtocol 设置项区分, NSURLProtocol 是通过registerClass方式将protocol实现的进行注册。  
  1. - (STMURLCache *)configWithMk {
  2.     self.mk.cModel.isSavedOnDisk = YES;
  3.     if (self.mk.cModel.isUsingURLProtocol) {
  4.         STMURLCacheModel *sModel = [STMURLCacheModel shareInstance];
  5.         sModel.cacheTime = self.mk.cModel.cacheTime;
  6.         sModel.diskCapacity = self.mk.cModel.diskCapacity;
  7.         sModel.diskPath = self.mk.cModel.diskPath;
  8.         sModel.cacheFolder = self.mk.cModel.cacheFolder;
  9.         sModel.subDirectory = self.mk.cModel.subDirectory;
  10.         sModel.whiteUserAgent = self.mk.cModel.whiteUserAgent;
  11.         sModel.whiteListsHost = self.mk.cModel.whiteListsHost;
  12.         [NSURLProtocol registerClass:[STMURLProtocol class]];
  13.     } else {
  14.         [NSURLCache setSharedURLCache:self];
  15.     }
  16.     return self;
  17. }
复制代码
关闭时两者也是不同的,通过设置项进行区分
  1. - (void)stop {
  2.     if (self.mk.cModel.isUsingURLProtocol) {
  3.         [NSURLProtocol unregisterClass:[STMURLProtocol class]];
  4.     } else {
  5.         NSURLCache *c = [[NSURLCache alloc] initWithMemoryCapacity:0 diskCapacity:0 diskPath:nil];
  6.         [NSURLCache setSharedURLCache:c];
  7.     }
  8.     [self.mk.cModel checkCapacity];
  9. }
复制代码
白名单处理还有读取缓存和前者都类似,但是在缓存Data时    NSURLCached的方案里是通过发起一次新的请求来获取数据,而    NSURLProtocol在    NSURLConnection的 Delegate 里可以获取到,少了一次网络的请求,这里需要注意的是在 - (void) connection:(NSURLConnection    )connection didReceiveData:(NSData)data 每次从这个回调里获取的数据不是完整的,要在 - (void) connectionDidFinishLoading:(NSURLConnection *)connection 这个会调里将分段数据拼接成完整的数据保存下来。具体完整的代码实现可以看 STMURLProtocol 里的代码实现。  
  后记

  通过    map网络请求可以缓存请求,也可以    mock接口请求进行测试。  
  完整代码:<    GitHub - ming1016/STMURLCache: iOS预加载Web页面方案>
友荐云推荐




上一篇:Linux强化论:15步打造一个安全的Linux服务器
下一篇:不仅是 Linux,盛大专家全面探究运维最佳实践
酷辣虫提示酷辣虫禁止发表任何与中华人民共和国法律有抵触的内容!所有内容由用户发布,并不代表酷辣虫的观点,酷辣虫无法对用户发布内容真实性提供任何的保证,请自行验证并承担风险与后果。如您有版权、违规等问题,请通过"联系我们"或"违规举报"告知我们处理。

*滑动验证:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

我要投稿

推荐阅读

扫码访问 @iTTTTT瑞翔 的微博
回页顶回复上一篇下一篇回列表手机版
手机版/CoLaBug.com ( 粤ICP备05003221号 | 文网文[2010]257号 )|网站地图 酷辣虫

© 2001-2016 Comsenz Inc. Design: Dean. DiscuzFans.

返回顶部 返回列表