一.项目需求

项目中有个海报功能,是用UIWebView加载h5网页的形式。因为海报的使用率比较高,如果网页加载得比较慢会严重影响用户体验,因此我们想了一个方法,在用户启动APP后,如果连接了Wi-Fi,就将一些css和图片资源,先下载到本地,在加载网页内容时,优先使用本地的css和图片,以加快网页载入速度。

实现原理:
拦截所有Http请求,并伪造Http请求。我们只需要写一个继承自 NSURLProtocol 的类并注册。在Http请求开始时,系统就会通过此类对请求进行处理。

二.Demo:百度首页的logo替换为本地图片

下面demo实现:加载百度的首页,百度logo图片改用本地提前下载好的图片代替。

(一) 注册JXURLProtocol类

  1. 新建JXURLProtocol类,继承自NSURLProtocol
@interface JXURLProtocol : NSURLProtocol@end
  1. 在加载网页前,注册JXURLProtocol类:
 NSURL *url = [NSURL URLWithString:@"https://www.baidu.com"];NSURLRequest *request = [NSURLRequest requestWithURL:url];[NSURLProtocol registerClass:[JXURLProtocol class]];[self.webView loadRequest:request];

(二 )拦截请求

  1. 在JXURLProtocol.m中实现canInitWithRequest:方法,所有请求都会先调用此方法,返回NO表示自己需要通过自己处理,正常发出请求,否则不发出请求,因为需要经过JXURLProtocol处理。
    我们需要拦截百度图片url的请求,即在canInitWithRequest:方法中,根据url判断,如果是百度logo图的url(https://m.baidu.com/static/index/plus/plus_logo.png), 返回YES,表示先不发出请求而是自己处理:
+ (BOOL)canInitWithRequest:(NSURLRequest *)request{NSString *urlString = request.URL.absoluteString;    //此处防止重复拦截(与后面的三(3)对应)if ([NSURLProtocol propertyForKey:@"JXProtocol" inRequest:request]) {return NO;}if ([urlString isEqualToString:@"https://m.baidu.com/static/index/plus/plus_logo.png"]) {return YES;}return NO;
}
  1. 上一步返回YES后,会继续执行方法:
- (void)startLoading{}

(三) 返回本地图片

  1. 根据请求的url获取本地对应的图片:
- (NSData*)imageDataWithUrl:(NSURL*)url{if ([url.absoluteString isEqualToString:@"https://m.baidu.com/static/index/plus/plus_logo.png"]) {NSString *filePath = [[NSBundle mainBundle] pathForResource:@"long" ofType:@"png"];NSData *data = [NSData dataWithContentsOfFile:filePath];return data;}return nil;
}
  1. 尝试获取本地图片,获取成功后,构建响应头,回调请求成功。
- (void)startLoading{NSData *imageData = [self imageDataWithUrl:self.request.URL];if (imageData) {//获取本地图片成功//构建请求头NSString *mimeType = @"image/jpeg";NSMutableDictionary *header = [NSMutableDictionary dictionary];NSString *contentType = [mimeType stringByAppendingString:@";chartset=UTF-8"];header[@"Content-type"] = contentType;header[@"Content-Length"] = [NSString stringWithFormat:@"%ld",imageData.length];NSHTTPURLResponse *response = [[NSHTTPURLResponse alloc] initWithURL:self.request.URLstatusCode:200 HTTPVersion:@"1.1" headerFields:header];//回调[self.client URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageAllowed];[self.client URLProtocol:self didLoadData:imageData];[self.client URLProtocolDidFinishLoading:self];}else{//获取本地图片失败}
}
  1. 如果获取本地图片失败,设置标志防止重复拦截,并重新构建请求来请求线上的资源:
- (void)startLoading{NSData *imageData = [self imageDataWithUrl:self.request.URL];if (imageData) {//获取本地图片成功//...}else{[NSURLProtocol setProperty:@(YES) forKey:@"JXProtocol" inRequest:self.request];NSMutableURLRequest *newRequset = [self.request mutableCopy];NSURLSessionConfiguration *config = [NSURLSessionConfiguration ephemeralSessionConfiguration];NSURLSession *session = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:[NSOperationQueue mainQueue]];NSURLSessionTask *task = [session dataTaskWithRequest:newRequset];[task resume];}
}
  1. 最后补上实现必须的方法:
+ (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request {return request;
}- (void)stopLoading{
}#pragma mark- NSURLConnectionDelegate- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {[self.client URLProtocol:self didFailWithError:error];
}#pragma mark - NSURLConnectionDataDelegate- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{[self.client URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed];
}- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {[self.client URLProtocol:self didLoadData:data];
}- (void)connectionDidFinishLoading:(NSURLConnection *)connection {[self.client URLProtocolDidFinishLoading:self];
}
  1. 运行APP,百度的logo已经换成本地的long.png,小恐龙了:

完整代码:https://github.com/dolacmeng/NSURLProtocolDemo

参考资料:
https://developer.apple.com/documentation/foundation/url_loading_system
https://github.com/draveness/analyze/blob/master/contents/OHHTTPStubs/iOS 开发中使用 NSURLProtocol 拦截 HTTP 请求.md

【iOS】通过NSURLProtocol提高Web加载速度相关推荐

  1. 【PHP】如何提高网页加载速度?

    [php]如何提高网页加载速度? 1.减少页面请求: 从WEB运行原理上讲,IIS请求是无状态的,在服务器端一直是连接和关闭的不断进行着,如果能减少服务器请求,总的时间将会减少. 之前我下载163邮箱 ...

  2. android加载h5速度慢的解决方案,WebView优化提高H5加载速度方案

    WebView优化提高H5加载速度方案 WebView加载H5经历的过程图示 上图体现的是用户打开一个H5页面,经历的过程与代码内部所作的事情的对应关系.javascript 用户:无感知(WebVi ...

  3. 如何提高页面加载速度 || 前端的性能优化 || 浏览器渲染页面的过程是什么

    1.降低请求量 ​ ① 合并资源,减少http请求数量. ​② lazyLoad,如图片懒加载.分批加载,每次只加载一部分. ​ ③ 使用字体图标或CSS绘制,来代替部分图片. 2.加快请求速度 ​ ...

  4. 前端性能优化——如何提高页面加载速度?

    1.将样式表放在头部 首先说明一下,将样式表放在头部对于实际页面加载的时间并不能造成太大影响,但是这会减少页面首屏出现的时间,使页面内容逐步呈现,改善用户体验,防止"白屏". 我们 ...

  5. Windows下使用apache模块实现合并多个js、css提高网页加载速度

    这篇文章主要介绍了Windows下使用apache模块实现合并多个js.css提高网页加载速度,本文使用的模块是基于mod_concat自己修改的,需要的朋友可以参考下 现在的网站表现力越来越丰富,页 ...

  6. 网页速度很慢优化方案:如何提高网页加载速度,提升网站加载速度

    网站加载速度的快慢,直接影响用户的去留.这里为大家持续更新我的经验,帮你解决网页速度很慢,慢在哪里,该怎么优化的问题.希望对你有所帮助! 1.  网站空间要好:网站需要一个稳定的服务器或者虚拟机,可以 ...

  7. HTML 提高页面加载速度的方法

    HTML 提高页面加载速度的方法: 1. 减少http请求(合并资源文件,合并图片-精灵图) 2. 把css放文件头部,javascript放body标签尾部 3. 定义图片的宽,高 4. 避免空的s ...

  8. vue-cli新建工程后提高页面加载速度(含升级webpack4)

    2019独角兽企业重金招聘Python工程师标准>>> 提高页面加载速度的方式 升级webpack4.x及升级过程中产生问题的解决方式 webpack升级一路填坑记 图片压缩 用一个 ...

  9. 提高网页加载速度的一些方法和技巧

    网页的加载速度是评估网站质量一个重要指标,原因在于大多数用户能够容忍的网页加载时间只有几秒,如果超出了访客的忍受范围他们会毫不留情地关掉你的网页,所以网页载入速度会极大地影响网站的流量和访问. 以下总 ...

最新文章

  1. 底部固定菜单_【悬浮菜单】安卓悬浮amp;手势助手
  2. eclipse java8报错_eclipse4.3安装支持Java8插件,之后就报错无法打开eclipse,求解?
  3. 10月了,聊聊我今年参加秋招的真实感受
  4. P2550 [AHOI2001]彩票摇奖
  5. ubuntu安装vasp_用强大的GROMACS分析工具分析VASP的动力学结果
  6. 20140505 科技脉搏 - “社交”这棵老树,依然在开着新花
  7. python怎么解压_Python-解压缩的方法
  8. validation problems were found problem cvc-complex-type.2.4a
  9. 【语音识别】基于matlab特定人的语音识别分辨【含Matlab源码 534期】
  10. 计算机考试一级b软件未来教育,2019.9全国计算机一级MS Office考试每日一练
  11. python补考卷子_1819级计算机专业补考(python程序设计)_章节测验,期末考试,慕课答案查询公众号...
  12. 公司技术分享-全文技术分享Lucene VS ElasticSearch VS Solr
  13. 计算机专业毕业论文格式,2016年计算机专业毕业论文内容及格式要求
  14. 外贸客户来源的渠道有哪些?
  15. 82. 采用 OPA5 开发支持页面跳转的 SAP UI5 集成测试用例
  16. 如何在安卓上android studio上构建本地服务器
  17. Android11 HAL层开发
  18. 零基础报成都java培训班需要学多久才能就业?
  19. 魔兽世界服务器显示负载离线,《WOW》服务器负载过高 官方免费转服
  20. 外语学习的真实方法与误区18

热门文章

  1. [.Net跨平台]部署DTCMS到Jexus遇到的问题及解决思路---Linux环境搭建
  2. 异步编程之Promise(2):探究原理
  3. 微软2014校园招聘笔试试题
  4. 转【红帽GFS集群文件系统配置指南】
  5. Martin Fowler对全世界程序员的建议
  6. 提升网络安全 十大策略全面巩固企业内网
  7. ISP 【一】————boost标准库使用——批量读取保存文件 /boost第三方库的使用及其cmake添加,图像gramma
  8. android 图片水印处理 文字倾斜处理
  9. Web 开发与设计之 Google 兵器谱
  10. 第四层到第七层的高层交换技术及其应用