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

欢迎加好友、一起交流。

时间: 2024-10-25 18:51:21

iOS H5容器的一些探究(二):iOS 下的黑魔法 NSURLProtocol的相关文章

iOS H5 容器的一些探究(一):UIWebView 和 WKWebView 的比较和选择

来源:景铭巴巴 链接:http://www.jianshu.com/p/84a6b1ac974a 一.Native开发中为什么需要H5容器 Native开发原生应用是手机操作系统厂商(目前主要是苹果的iOS和google的Android)对外界提供的标准化的开发模式,他们对于native开发提供了一套标准化实现和优化方案.但是他们存在一些硬伤,比如App的发版周期偏长.有时无法跟上产品的更新节奏:灵活性差,如果有较大的方案变更,需要发版才能解决:如果存在bug,在当前版本修复的难度比较大(iOS

iOS H5容器的一些探究(一):UIWebView和WKWebView的比较和选择

一.Native开发中为什么需要H5容器 Native开发原生应用是手机操作系统厂商(目前主要是苹果的iOS和google的Android)对外界提供的标准化的开发模式,他们对于native开发提供了一套标准化实现和优化方案.但是他们存在一些硬伤,比如App的发版周期偏长.有时无法跟上产品的更新节奏:灵活性差,如果有较大的方案变更,需要发版才能解决:如果存在bug,在当前版本修复的难度比较大(iOS的JSPatch方案和Android的Dex修复方案);需要根据不同的平台写不同的代码,iOS主要

iOS - UIWebView和WKWebView的比较和选择-作为H5容器的一些探究

一.Native开发中为什么需要H5容器 Native开发原生应用是手机操作系统厂商(目前主要是苹果的iOS和google的Android)对外界提供的标准化的开发模式,他们对于native开发提供了一套标准化实现和优化方案.但是他们存在一些硬伤,比如App的发版周期偏长.有时无法跟上产品的更新节奏:灵活性差,如果有较大的方案变更,需要发版才能解决:如果存在bug,在当前版本修复的难度比较大(iOS的JSPatch方案和Android的Dex修复方案);需要根据不同的平台写不同的代码,iOS主要

李洪强iOS之集成极光推送二iOS 证书 设置指南

p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 18.0px "PingFang SC"; color: #000000 } span.s1 { } span.s2 { font: 18.0px Menlo } 创建应用程序ID 登陆 iOS Dev Center 选择进入iOS Provisioning Portal. 在 iOS Provisioning Portal中,点击App IDs进入App ID列表. 创建 App ID,如果

iOS runtime探究(二): 从runtime開始深入理解OC消息转发机制

你要知道的runtime都在这里 转载请注明出处 http://blog.csdn.net/u014205968/article/details/67639289 本文主要解说runtime相关知识,从原理到实践.由于包括内容过多分为下面五篇文章详细解说.可自行选择须要了解的方向: 从runtime開始: 理解面向对象的类到面向过程的结构体 从runtime開始: 深入理解OC消息转发机制 从runtime開始: 理解OC的属性property 从runtime開始: 实践Category加入属

iOS知识点、面试题 之二

最近面试,发现这些题个人约到的几率打一些,与大家分享一下,分三文给大家: 当然Xcode新版本区别,以及iOS新特性 Xcode8 和iOS 10 在之前文章有发过,感兴趣的可以查阅: http://www.cnblogs.com/xujiahui/p/6025830.html 不足之处望见谅. 之二: 1.怎么样适配ios系统和ios屏幕 ios适配系统代码写法[[UIDevice currentDevice] systemVersion] 和NSFoundationVersionNumber

【iOS开发每日小笔记(二)】gitHub上的开源“瀑布流”使用心得

这篇文章是我的[iOS开发每日小笔记]系列中的一片,记录的是今天在开发工作中遇到的,可以用很短的文章或很小的demo演示解释出来的小心得小技巧.该分类的文章,内容涉及的知识点可能是很简单的.或是用很短代码片段就能实现的,但在我看来它们可能会给用户体验.代码效率得到一些提升,或是之前自己没有接触过的技术,很开心的学到了,放在这里得瑟一下(^_^).其实,90%的作用是帮助自己回顾.记忆.复习.如果看官觉得太easy,太碎片,则可以有两个选择:1,移步[iOS探究]分类,对那里的文章进行斧正:2,在

IOS-沙盒机制(二 文件读写)

一 目录说明 如下图所示,一个沙盒中典型存在下面的目录和文件 各个目录及文件说明: 1.Documents      您应该将所有的应用程序数据文件写入到这个目录下,这个目录用于存储用户数据或其它应该定期备份的信息. 2.AppName.app   这是应用程序的程序包目录,包含应用程序的本身.由于应用程序必须经过签名,所以您在运行时不能对这个目录中的内容进行修改,否则可能会使应用程序无法启动. 3.Library              这个目录下有两个子目录:Caches 和 Prefer

iOS系列 基础篇 03 探究应用生命周期

iOS系列 基础篇 03 探究应用生命周期 目录: 1. 非运行状态 - 应用启动场景 2. 点击Home键 - 应用退出场景 3. 挂起重新运行场景 4. 内存清除 - 应用终止场景 5. 结尾 本篇主要探讨的是iOS应用中各种状态的跃迁过程,建议大家通过修改AppDelegate.swift,在每个过程中添加日志输出代码,从而观察其变化. 作为应用程序的委托对象,AppDelegate类在应用程序生命周期的不同阶段会回调不同的方法. 首先,咱们先来了解一下iOS应用的不同状态和他们之间的关系