一.场景
整个工程中中图片url需要添加额外的参数支持图片优化,包括webview部分。
二.方案
所以使用NSURLProtocol拦截相关URL,替换http请求,实现图片优化参数的统一支持。
三.详细实现
1.声明继承NSURLProtocol的子类QImageURLProtocol.
头文件内容如下:
1
2
3
4
5
6
7
8
9
10
11
12
|
/**
* 用于测试的url
*/
static NSString *KPicBURL = @"http://g.hiphotos.baidu.com/image/h%3D800%3Bcrop%3D0%2C0%2C1280%2C800/sign=ee4c561ac1fdfc03fa78eeb8e404e4e6/a686c9177f3e6709ef8de51b39c79f3df9dc5540.jpg";
static NSString *KPicAURL = @"http://d.hiphotos.baidu.com/image/h%3D800%3Bcrop%3D0%2C0%2C1280%2C800/sign=ee81c70e83cb39dbdec06a56e02d6a56/b812c8fcc3cec3fdcf460491d488d43f869427dd.jpg";
@interface QImageURLProtocol : NSURLProtocol
@end
|
2.实现文件内容
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
|
@interface QImageURLProtocol ()
@property (nonatomic, strong) NSURLConnection *connection;
@end
@implementation QImageURLProtocol
#pragma mark -----------NSURLProtocol-------------
+(BOOL)canInitWithRequest:(NSURLRequest *)request{
NSLog(@"----origin request url = %@",request.URL.absoluteString);
if ([self isQImageURLRequest:request]) {
return YES;
}
return NO;
}
+(NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request{
NSMutableURLRequest *cdnRequest = [request mutableCopy];
cdnRequest.URL = [self imagesForQImageURL:request.URL];
//[NSURLProtocol setProperty:@"YES" forKey:@"QImageURL" inRequest:cdnRequest];
return cdnRequest;
}
- (void)startLoading {
self.connection = [NSURLConnection connectionWithRequest:[QImageURLProtocol canonicalRequestForRequest:self.request ] delegate:self];
}
- (void)stopLoading {
[self.connection cancel];
self.connection = nil;
}
- (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];
}
#pragma mark -----------------private method---------
+(BOOL)isQImageURLRequest:(NSURLRequest*)request{
if ( [request.URL.host isEqualToString:@"d.hiphotos.baidu.com"]
//&&nil == [NSURLProtocol propertyForKey:@"QImageURL" inRequest:request]
)
{
NSLog(@"isQImageURLRequest");
return YES;
}
return NO;
}
+(NSURL*)imagesForQImageURL:(NSURL*)url{
//只要是KPicAURL,会被直接替换为KPicBURL
if ([url.host isEqualToString:@"d.hiphotos.baidu.com" ]
&& [url.absoluteString isEqualToString:KPicAURL ]) {
NSLog(@"----real request url = %@",KPicBURL);
return [NSURL URLWithString:KPicBURL];
};
return url;
}
@end
|
3.调用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
- (void)dealloc
{
[NSURLProtocol unregisterClass:[QImageURLProtocol class]];
}
- (void)viewDidLoad
{
[super viewDidLoad];
//关键一步
[NSURLProtocol registerClass:[QImageURLProtocol class]];
_imageDownloadQueue = [[NSOperationQueue alloc] init];
}
-(IBAction)requestImageEvent:(id)sender
{
NSURLRequest *request = [ NSURLRequest requestWithURL:[NSURL URLWithString:KPicAURL]];
[NSURLConnection sendAsynchronousRequest:request queue:_imageDownloadQueue completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
if (nil == connectionError) {
UIImage *image = [UIImage imageWithData:data];
dispatch_async(dispatch_get_main_queue(), ^{
_imageView.image = image;
});
}
}];
}
|
四.注意事项
1.拦截有效性
这种方法对于基于NSURLConnection的http请求是有效的,例如AFNetworking,对于基于CFNetwork框架的是不支持的,例如:MKNetworkKit,ASIHttpRequest
2.拦截范围
无论对webView还是native的,只要是基于NSURLConnection的网络请求的,可以根据相关特征进行URL拦截替换.
3.多次拦截注入
如果一个工程当中,注册了多个拦截基于NSURLConnection的网络请求的类的情况下,最终生效的是最后拦截者。
文章作者
梵梵爸
上次更新
2014-08-05
许可协议
原创文章,如需转载请注明文章作者和出处。谢谢