您的位置:首页 > 移动开发

通过重写NSURLProtocol实现UIWebView的数据缓存

2016-08-16 19:15 417 查看
由于公司项目是混合开发,基本上全部是通过UIWebView加载的,虽然这样减轻了客户端的工作量,但是,不可避免会遇到网络差,服务器不稳定等的情况,在这种情况下,webView的加载效果就很差了,严重影响客户体验,于是产品经理要求研究客户端的优化、缓存问题。网上是找了一个NSURLProtocol的缓存的思路的,但是到今天实际上手操作的时候就遇到问题了。今天下午就好好研究了一下,终于把问题搞定了。下面开始正文:

一、NSURLProtocol 简介

其实网上关于NSURLProtocol的介绍已经很好很详细了,我就不做过多介绍了,说最主要的一点,你可以通过继承NSURLProtocol,自定义一个子类,然后可以轻松的重新定义苹果的URL加载系统 (URL Loading System)的行为。通过拦截,可以实现各种操作

二、实现的主要步骤

首先,要在AppDelegate.m的- (BOOL)application:(UIApplication )application didFinishLaunchingWithOptions:(NSDictionary )launchOptions 里面进行注册

[NSURLProtocol registerClass:[MyConnectionURLProtocol class]];

然后,重写NSURLProtocol的方法

+ (BOOL)canInitWithRequest:(NSURLRequest *)request;

每个请求都会进入这个方法,返回YES表示接管系统请求,自己进行相关操作,返回NO,表示,默认系统的请求。我们可以在这个方法里面判断自己需要做处理的连接,可以根据实现webView缓存,判断要加载的资源在本地是否存在,如果存在,接管系统请求,加载本地资源

+ (BOOL)canInitWithRequest:(NSURLRequest *)request {

/*
防止无限循环,因为一个请求在被拦截处理过程中,也会发起一个请求,这样又会走到这里,如果不进行处理,就会造成无限循环
*/
if ([NSURLProtocol propertyForKey:protocolKey inRequest:request]) {
return NO;
}
NSString * url = request.URL.absoluteString;
// 如果url已http或https,开头,则进行拦截处理,否则不处理
if ([url hasPrefix:@"http"] || [url hasPrefix:@"https"]) {
//判断要加载的资源本地是否存在
if ([MyConnectionURLProtocol localResourceIsExistWith:request]) {
return YES;
} else {
return NO;
}

}
return NO;
}


这是相应的判断。

当上面的操作返回为YES的时候,才会继续下面的操作。

- (void)startLoading重写该方法,需要在该方法中发起一个请求,对于NSURLConnection来说,就是创建一个NSURLConnection,对于NSURLSession,就是发起一个NSURLSessionTask,在这里可以进行相关的操作,加载本地资源

NSMutableURLRequest * request = [self.request mutableCopy];
// 表示该请求已经被处理,防止无限循环
[NSURLProtocol setProperty:@(YES) forKey:protocolKey inRequest:request];
NSLog(@"URL %@",request.URL.absoluteString);
NSString *str = request.URL.path;
NSString *Regex = nil;
if ([str.pathExtension isEqualToString:@"js"])
{
Regex = [MyConnectionURLProtocol addLocalFileReturnRex:@"js"];

}else if ([str.pathExtension isEqualToString:@"css"])
{
Regex = [MyConnectionURLProtocol addLocalFileReturnRex:@"css"];

}else if ([str.pathExtension isEqualToString:@"jpg"]||[str.pathExtension isEqualToString:@"png"])
{
Regex = [MyConnectionURLProtocol addLocalFileReturnRex:@"img"];

}

[MyConnectionURLProtocol rexString:str rex:Regex success:^(NSString *matchStr) {

NSArray *fileArr = [matchStr componentsSeparatedByString:@"."];
[self addFiledToClient:matchStr MIMEType:fileArr.lastObject];

} faild:^{

self.connection = [NSURLConnection connectionWithRequest:request delegate:self];
}];


重写- (void)stopLoading该方法,需要停止响应的请求

- (void)stopLoading {
[self.connection cancel];
}


此外,还要重写+ (NSURLRequest )canonicalRequestForRequest:(NSURLRequest )request该方法,可以增加或修改请求头等操作,主要是改变request的操作

+ (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request {

// 修改了请求的头部信息
NSMutableURLRequest *mutableReqeust = [request mutableCopy];
mutableReqeust = [self redirectHostInRequset:mutableReqeust];
return mutableReqeust;
}


三、实现NSURLConnectionDataDelegate协议代理方

#pragma mark - NSURLConnectionDelegate

- (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];
}


以上操作就可以实现UIWebView的缓存,谢谢观看
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: