【iOS】通过NSURLProtocol提高Web加载速度
一.项目需求
项目中有个海报功能,是用UIWebView加载h5网页的形式。因为海报的使用率比较高,如果网页加载得比较慢会严重影响用户体验,因此我们想了一个方法,在用户启动APP后,如果连接了Wi-Fi,就将一些css和图片资源,先下载到本地,在加载网页内容时,优先使用本地的css和图片,以加快网页载入速度。
实现原理:
拦截所有Http请求,并伪造Http请求。我们只需要写一个继承自 NSURLProtocol 的类并注册。在Http请求开始时,系统就会通过此类对请求进行处理。
二.Demo:百度首页的logo替换为本地图片
下面demo实现:加载百度的首页,百度logo图片改用本地提前下载好的图片代替。
(一) 注册JXURLProtocol类
- 新建JXURLProtocol类,继承自NSURLProtocol
@interface JXURLProtocol : NSURLProtocol@end
- 在加载网页前,注册JXURLProtocol类:
NSURL *url = [NSURL URLWithString:@"https://www.baidu.com"];NSURLRequest *request = [NSURLRequest requestWithURL:url];[NSURLProtocol registerClass:[JXURLProtocol class]];[self.webView loadRequest:request];
(二 )拦截请求
- 在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;
}
- 上一步返回YES后,会继续执行方法:
- (void)startLoading{}
(三) 返回本地图片
- 根据请求的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;
}
- 尝试获取本地图片,获取成功后,构建响应头,回调请求成功。
- (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{//获取本地图片失败}
}
- 如果获取本地图片失败,设置标志防止重复拦截,并重新构建请求来请求线上的资源:
- (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];}
}
- 最后补上实现必须的方法:
+ (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];
}
- 运行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加载速度相关推荐
- 【PHP】如何提高网页加载速度?
[php]如何提高网页加载速度? 1.减少页面请求: 从WEB运行原理上讲,IIS请求是无状态的,在服务器端一直是连接和关闭的不断进行着,如果能减少服务器请求,总的时间将会减少. 之前我下载163邮箱 ...
- android加载h5速度慢的解决方案,WebView优化提高H5加载速度方案
WebView优化提高H5加载速度方案 WebView加载H5经历的过程图示 上图体现的是用户打开一个H5页面,经历的过程与代码内部所作的事情的对应关系.javascript 用户:无感知(WebVi ...
- 如何提高页面加载速度 || 前端的性能优化 || 浏览器渲染页面的过程是什么
1.降低请求量 ① 合并资源,减少http请求数量. ② lazyLoad,如图片懒加载.分批加载,每次只加载一部分. ③ 使用字体图标或CSS绘制,来代替部分图片. 2.加快请求速度 ...
- 前端性能优化——如何提高页面加载速度?
1.将样式表放在头部 首先说明一下,将样式表放在头部对于实际页面加载的时间并不能造成太大影响,但是这会减少页面首屏出现的时间,使页面内容逐步呈现,改善用户体验,防止"白屏". 我们 ...
- Windows下使用apache模块实现合并多个js、css提高网页加载速度
这篇文章主要介绍了Windows下使用apache模块实现合并多个js.css提高网页加载速度,本文使用的模块是基于mod_concat自己修改的,需要的朋友可以参考下 现在的网站表现力越来越丰富,页 ...
- 网页速度很慢优化方案:如何提高网页加载速度,提升网站加载速度
网站加载速度的快慢,直接影响用户的去留.这里为大家持续更新我的经验,帮你解决网页速度很慢,慢在哪里,该怎么优化的问题.希望对你有所帮助! 1. 网站空间要好:网站需要一个稳定的服务器或者虚拟机,可以 ...
- HTML 提高页面加载速度的方法
HTML 提高页面加载速度的方法: 1. 减少http请求(合并资源文件,合并图片-精灵图) 2. 把css放文件头部,javascript放body标签尾部 3. 定义图片的宽,高 4. 避免空的s ...
- vue-cli新建工程后提高页面加载速度(含升级webpack4)
2019独角兽企业重金招聘Python工程师标准>>> 提高页面加载速度的方式 升级webpack4.x及升级过程中产生问题的解决方式 webpack升级一路填坑记 图片压缩 用一个 ...
- 提高网页加载速度的一些方法和技巧
网页的加载速度是评估网站质量一个重要指标,原因在于大多数用户能够容忍的网页加载时间只有几秒,如果超出了访客的忍受范围他们会毫不留情地关掉你的网页,所以网页载入速度会极大地影响网站的流量和访问. 以下总 ...
最新文章
- 底部固定菜单_【悬浮菜单】安卓悬浮amp;手势助手
- eclipse java8报错_eclipse4.3安装支持Java8插件,之后就报错无法打开eclipse,求解?
- 10月了,聊聊我今年参加秋招的真实感受
- P2550 [AHOI2001]彩票摇奖
- ubuntu安装vasp_用强大的GROMACS分析工具分析VASP的动力学结果
- 20140505 科技脉搏 - “社交”这棵老树,依然在开着新花
- python怎么解压_Python-解压缩的方法
- validation problems were found problem cvc-complex-type.2.4a
- 【语音识别】基于matlab特定人的语音识别分辨【含Matlab源码 534期】
- 计算机考试一级b软件未来教育,2019.9全国计算机一级MS Office考试每日一练
- python补考卷子_1819级计算机专业补考(python程序设计)_章节测验,期末考试,慕课答案查询公众号...
- 公司技术分享-全文技术分享Lucene VS ElasticSearch VS Solr
- 计算机专业毕业论文格式,2016年计算机专业毕业论文内容及格式要求
- 外贸客户来源的渠道有哪些?
- 82. 采用 OPA5 开发支持页面跳转的 SAP UI5 集成测试用例
- 如何在安卓上android studio上构建本地服务器
- Android11 HAL层开发
- 零基础报成都java培训班需要学多久才能就业?
- 魔兽世界服务器显示负载离线,《WOW》服务器负载过高 官方免费转服
- 外语学习的真实方法与误区18
热门文章
- [.Net跨平台]部署DTCMS到Jexus遇到的问题及解决思路---Linux环境搭建
- 异步编程之Promise(2):探究原理
- 微软2014校园招聘笔试试题
- 转【红帽GFS集群文件系统配置指南】
- Martin Fowler对全世界程序员的建议
- 提升网络安全 十大策略全面巩固企业内网
- ISP 【一】————boost标准库使用——批量读取保存文件 /boost第三方库的使用及其cmake添加,图像gramma
- android 图片水印处理 文字倾斜处理
- Web 开发与设计之 Google 兵器谱
- 第四层到第七层的高层交换技术及其应用