iOS H5容器的一些探究(二):iOS 下的黑魔法 NSURLProtocol
来源:景铭巴巴
链接:http://www.jianshu.com/p/03ddcfe5ebd7
iOS H5 容器的一些探究(一):UIWebView 和 WKWebView 的比较和选择
一、前言
NSURLProtocol是iOS中URL Loading System的一部分。如果开发者自定义的一个NSURLProtocol并且注册到app中,那么在这个自定义的NSURLProtocol中我们可以拦截UIWebView,基于系统的NSURLConnection或者NSURLSession进行封装的网络请求,然后做到自定义的response返回。非常强大。
二、NSURLProtocol的使用流程
2.1、在AppDelegate中注册自定义的NSURLProtocol。
比如我这边自定义的NSURLProtocol叫做YXNSURLProtocol。
@interface YXNSURLProtocol : NSURLProtocol
@end
在系统加载的时候,把自定义的YXNSURLProtocol注册到URL加载系统中,这样 所有的URL请求都有机会进入我们自定义的YXNSURLProtocol进行拦截处理。
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[NSURLProtocol registerClass:[YXNSURLProtocol class]];
}
加载完成后,当产生URL请求的同时,会依次进入NSURLProtocol的以下相关方法进行处理,下面我们依次来讲一下每一个方法的作用。
2.2、NSURLProtocol中的几个方法
2.2.1、是否进入自定义的NSURLProtocol加载器
+ (BOOL)canInitWithRequest:(NSURLRequest *)request{
BOOL intercept = YES;
NSLog(@"YXNSURLProtocol==%@",request.URL.absoluteString);
if (intercept) {
}
return intercept;
}
如果返回YES则进入该自定义加载器进行处理,如果返回NO则不进入该自定义选择器,使用系统默认行为进行处理。
如果这一步骤返回YES。则会进入2.3的方法中。
2.2.2、重新设置NSURLRequest的信息
+ (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request {
return request;
}
在这个方法中,我们可以重新设置或者修改request的信息。比如请求重定向或者添加头部信息等等。如果没有特殊需求,直接返回request就可以了。但是因为这个方法在会在一次请求中被调用多次(暂时我也不知道什么原因为什么需要回调多洗),所以request重定向和添加头部信息也可以在开始加载中startLoading方法中重新设置。
2.2.3、这个方法主要是用来判断两个request是否相同,如果相同的话可以使用缓存数据,通常调用父类的实现即可
+ (BOOL)requestIsCacheEquivalent:(NSURLRequest *)a toRequest:(NSURLRequest *)b{
return [super requestIsCacheEquivalent:a toRequest:b];
}
这个方法基本不常用。
2.2.4、被拦截的请求开始执行的地方
- (void)startLoading{
}
这个函数使我们重点使用的函数。
2.2.5、结束加载URL请求
- (void)stopLoading{
}
2.3、NSURLProtocolClient中的几个方法
上面的NSURLProtocol定义了一系列加载的流程。而在每一个流程中,我们作为使用者该如何使用URL加载系统,则是NSURLProtocolClient中几个方法该做的事情。
@protocol NSURLProtocolClient
//请求重定向
- (void)URLProtocol:(NSURLProtocol *)protocol wasRedirectedToRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse;
// 响应缓存是否合法
- (void)URLProtocol:(NSURLProtocol *)protocol cachedResponseIsValid:(NSCachedURLResponse *)cachedResponse;
//刚接收到Response信息
- (void)URLProtocol:(NSURLProtocol *)protocol didReceiveResponse:(NSURLResponse *)response cacheStoragePolicy:(NSURLCacheStoragePolicy)policy;
//数据加载成功
- (void)URLProtocol:(NSURLProtocol *)protocol didLoadData:(NSData *)data;
//数据完成加载
- (void)URLProtocolDidFinishLoading:(NSURLProtocol *)protocol;
//数据加载失败
- (void)URLProtocol:(NSURLProtocol *)protocol didFailWithError:(NSError *)error;
//为指定的请求启动验证
- (void)URLProtocol:(NSURLProtocol *)protocol didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge;
//为指定的请求取消验证
- (void)URLProtocol:(NSURLProtocol *)protocol didCancelAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge;
@end
三、实现一个地址重定向的Demo
这个Demo实现的功能是在UIWebView中所有跳转到sina首页的请求,都重定位到sohu首页。
3.1、第一步,新建一个UIWebView,加载sina首页
_webView = [[UIWebView alloc] initWithFrame:self.view.bounds];
_webView.delegate = self;
[self.view addSubview:_webView];
NSURL *url = [[NSURL alloc] initWithString:@"https://sina.cn"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[_webView loadRequest:request];
3.2、自定义一个NSURLProtocol
@interface YXNSURLProtocolTwo : NSURLProtocol
@end
3.3、在AppDelegate中,进行注册
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[NSURLProtocol registerClass:[YXNSURLProtocolTwo class]];
return YES;
}
3.4、在canInitWithRequest方法中拦截https://sina.cn/
+ (BOOL)canInitWithRequest:(NSURLRequest *)request{
NSLog(@"canInitWithRequest url-->%@",request.URL.absoluteString);
//看看是否已经处理过了,防止无限循环
if ([NSURLProtocol propertyForKey:URLProtocolHandledKey inRequest:request]) {
return NO;
}
NSString *urlString = request.URL.absoluteString;
if([urlString isEqualToString:@"https://sina.cn/"]){
return YES;
}
return NO;
}
3.5、在startLoading中进行方法重定向
- (void)startLoading{
NSMutableURLRequest * request = [self.request mutableCopy];
// 标记当前传入的Request已经被拦截处理过,
//防止在最开始又继续拦截处理
[NSURLProtocol setProperty:@(YES) forKey:URLProtocolHandledKey inRequest:request];
self.connection = [NSURLConnection connectionWithRequest:[self changeSinaToSohu:request] delegate:self];
}
//把所用url中包括sina的url重定向到sohu
- (NSMutableURLRequest *)changeSinaToSohu:(NSMutableURLRequest *)request{
NSString *urlString = request.URL.absoluteString;
if ([urlString isEqualToString:@"https://sina.cn/"]) {
urlString = @"http://m.sohu.com/";
request.URL = [NSURL URLWithString:urlString];
}
return request;
}
你也可以选择在+ (NSURLRequest )canonicalRequestForRequest:(NSURLRequest )request替换request。效果都是一样的。
3.6、因为新建了一个NSURLConnection *connection,所以要实现他的代理方法,如下
- (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];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
[self.client URLProtocol:self didFailWithError:error];
}
通过以上几步,我们就可以实现最简单的url重定向,WebView加载新浪首页,却跳转到了搜狐首页。
四、小结
通过自定义的NSURLProtocol,我们拿到用户请求的request之后,我们可以做很多事情。比如:
1、自定义请求和响应
2、网络的缓存处理(H5离线包 和 网络图片缓存)
3、重定向网络请求
4、为测试提供数据Mocking功能,在没有网络的情况下使用本地数据返回。
5、过滤掉一些非法请求
6、快速进行测试环境的切换
7、拦截图片加载请求,转为从本地文件加载
8、可以拦截UIWebView,基于系统的NSURLConnection或者NSURLSession进行封装的网络请求。目前WKWebView无法被NSURLProtocol拦截。
9、当有多个自定义NSURLProtocol注册到系统中的话,会按照他们注册的反向顺序依次调用URL加载流程。当其中有一个NSURLProtocol拦截到请求的话,后续的NSURLProtocol就无法拦截到该请求。
五、联系方式
新浪微博:http://weibo.com/5612984599/info
github:https://github.com/yixiangboy
欢迎加好友、一起交流。
iOS H5容器的一些探究(二):iOS 下的黑魔法 NSURLProtocol的更多相关文章
- iOS H5 容器的一些探究(一):UIWebView 和 WKWebView 的比较和选择
来源:景铭巴巴 链接:http://www.jianshu.com/p/84a6b1ac974a 一.Native开发中为什么需要H5容器 Native开发原生应用是手机操作系统厂商(目前主要是苹果的 ...
- iOS H5容器的一些探究(一):UIWebView和WKWebView的比较和选择
一.Native开发中为什么需要H5容器 Native开发原生应用是手机操作系统厂商(目前主要是苹果的iOS和google的Android)对外界提供的标准化的开发模式,他们对于native开发提供了 ...
- 李洪强iOS之集成极光推送二iOS 证书 设置指南
李洪强iOS之集成极光推送二iOS 证书 设置指南 创建应用程序ID 登陆 iOS Dev Center 选择进入iOS Provisioning Portal. 在 iOS Provisioning ...
- iOS - UIWebView和WKWebView的比较和选择-作为H5容器的一些探究
一.Native开发中为什么需要H5容器 Native开发原生应用是手机操作系统厂商(目前主要是苹果的iOS和google的Android)对外界提供的标准化的开发模式,他们对于native开发提供了 ...
- iOS runtime探究(二): 从runtime開始深入理解OC消息转发机制
你要知道的runtime都在这里 转载请注明出处 http://blog.csdn.net/u014205968/article/details/67639289 本文主要解说runtime相关知识, ...
- iOS 转场动画探究(二)
这篇文章是接着第一篇写的,要是有同行刚看到的话建议从前面第一篇看,这是第一篇的地址:iOS 转场动画探究(一) 接着上一篇写的内容: 上一篇iOS 转场动画探究(一)我们说到了转场要素的第四点,把那个 ...
- bootsrtap h5 移动版页面 在苹果手机ios滑动上下拉动滚动卡顿问题解决方法
bootsrtap h5 移动版页面 在苹果手机ios滑动上下拉动滚动卡顿问题解决方法 bootsrtap框架做的h5页面,在android手机下没有卡顿问题,在苹果手机就一直存在这问题,开始毫无头绪 ...
- ios h5 app avalon tap点击事件失效及点击延迟300ms问题解决方法
1.ios h5 app avalon tap事件失效 使用MUI制作app界面,使用avalon.js渲染数据,发现在(Android上正常)ios上运行时容器div的avalon的ms-on-ta ...
- iOS知识点、面试题 之二
最近面试,与大家分享一下,分三文给大家: 当然Xcode新版本区别,以及iOS新特性 Xcode8 和iOS 10 在之前文章有发过,感兴趣的可以查阅: http://www.cnblogs.com/ ...
随机推荐
- c++一些问题总结
<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255) ...
- 【原】Hadoop伪分布模式的安装
Hadoop伪分布模式的安装 [环境参数] (1)Host OS:Win7 64bit (2)IDE:Eclipse Version: Luna Service Release 2 (4.4.2) ( ...
- [转]模拟HttpContext 实现ASP.NET MVC 的单元测试
众所周知 ASP.NET MVC 的一个显著优势即可以很方便的实现单元测试,但在我们测试过程中经常要用到HttpContext,而默认情况下单元测试框架是不提供HttpContext的模拟的,本文通过 ...
- labview视频采集IMAdx
grab(连续采集) 摄像头打开之后便一直采集图像,存储在IMAQ开辟的临时空间里,只要while循环不断的读取临时空间就可以显示当前图像(grab调用的是image句柄)
- AutoCAD.NET 不使用P/Invoke方式调用acad.exe或accore.dll中的接口(如acedCommand、acedPostCommand等)
使用C#进行AutoCAD二次开发,有时候由于C#接口不够完善,或者低版本AutoCAD中的接口缺少,有些工作不能直接通过C#接口来实现,所以需要通过P/Invoke的方式调用AutoCAD的其他DL ...
- [iOS微博项目 - 3.0] - 手动刷新微博
github: https://github.com/hellovoidworld/HVWWeibo A.下拉刷新微博 1.需求 在“首页”界面,下拉到一定距离的时候刷新微博数据 刷新数据的时候使 ...
- easyui反选全选和全不选代码以及方法的使用
首先要说明的是,onclick="javascript:这里能写方法的名字,也能写一段JS的代码,但是方法名字要带括号.",其次就是onclick=“这里写的方法名必须存在于本页面 ...
- 转载sublime text注册码
直接输入注册码就可以了 ----- BEGIN LICENSE ----- Andrew Weber Single User License EA7E-855605 813A03DD 5E4AD9E6 ...
- hdoj 5387(Clock)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5387 比较水的一道题目,也是自己单翘的第一道题目吧,题意就是找到给定时间时钟三个指针之间的夹角, 需要 ...
- 说下Fedora下把SpiderMonkey放入Eclipse内编译的过程
首先要知道SpiderMonkey是个什么玩意 详细的可以看看这里(当然,如果你有google翻译的话看起来也一样费劲,你可以在语言那里选择中文.看完了再转回英文-因为中文有很多文档都没有的,比如:B ...