网络
NSURLProtocol
/*!
@class NSURLProtocol
@abstract NSURLProtocol is an abstract class which provides the
basic structure for performing protocol-specific loading of URL
data. Concrete subclasses handle the specifics associated with one
or more protocols or URL schemes.
*/
抽象类
[NSURLProtocol registerClass:[KCURLProtocol class]];
// 这个方法是注册后,NSURLProtocol就会通过这个方法确定参数request是否需要被处理
// return : YES 需要经过这个NSURLProtocol"协议" 的处理, NO 这个 协议request不需要遵守这个NSURLProtocol"协议"
// 这个方法的作用 :
// -| 1, 筛选Request是否需要遵守这个NSURLRequest ,
// -| 2, 处理http: , https等URL
// 重定向
// 监听 - sdk -
+ (BOOL)canInitWithRequest:(NSURLRequest *)request{
NSLog(@"*** %@",request);
// md5
if ([NSURLProtocol propertyForKey:kcProtocolKey inRequest:request]) {
return NO;//自己的链接不需要hook,或者如果已经重定向过,就不需要在拦截了
}
// 直接hook 图片
NSArray *array = @[@"png",@"jpg",@"jpeg"];
if ([array containsObject:[request.URL pathExtension]]) {
return YES; //返回YES需要重定向,会调用startloading方法
}
// 拦截百度的logo
if ([[request.URL absoluteString] isEqualToString:@"https://m.baidu.com/static/index/plus/plus_logo_web.png"]) {
return YES;
}
if ([[request.URL absoluteString] isEqualToString:@"http://www.baidu.com/"]) {
return YES;
}
// 黑名单 -- 服务器 -- 本地
//
return NO;
}
// 需要在该方法中发起一个请求,对于NSURLConnection来说,就是创建一个NSURLConnection,对于NSURLSession,就是发起一个NSURLSessionTask
// 另外一点就是这个方法之后,会回调<NSURLProtocolClient>协议中的方法,
- (void)startLoading{
NSLog(@"%s",__func__);
NSArray *array = @[@"png",@"jpg",@"jpeg"];
// 广告
if ([array containsObject:[self.request.URL pathExtension]]) {
NSData *data = [self getImageData];
[self.client URLProtocol:self didLoadData:data];
}
// 拦截给与自己数据
if ([[self.request.URL absoluteString] isEqualToString:@"https://m.baidu.com/static/index/plus/plus_logo_web.png"]) {
NSData *data = [self getImageData];
[self.client URLProtocol:self didLoadData:data];
}
if ([[self.request.URL absoluteString] isEqualToString:@"http://www.baidu.com/"]) {
// NSString *url = @"http://127.0.0.1:8080/getMethod/";
NSString *url = @"http://127.0.0.1:8080";
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:url]];
[NSURLProtocol setProperty:@(YES) forKey:kcProtocolKey inRequest:request];//自己的链接不需要hook
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) {
NSLog(@"Connection - %@---%@",response,data);
}];
}
}
// NSURLProtocol 在AFN和Session拦截会失效,原因是session的协议里面没有NSURLProtocol,需要使用运行时交互方法添加。
#pragma mark - hook
+ (void)hookNSURLSessionConfiguration{
Class cls = NSClassFromString(@"__NSCFURLSessionConfiguration") ?: NSClassFromString(@"NSURLSessionConfiguration");
Method originalMethod = class_getInstanceMethod(cls, @selector(protocolClasses));
Method stubMethod = class_getInstanceMethod([self class], @selector(protocolClasses));
if (!originalMethod || !stubMethod) {
[NSException raise:NSInternalInconsistencyException format:@"没有这个方法 无法交换"];
}
method_exchangeImplementations(originalMethod, stubMethod);
}
- (NSArray *)protocolClasses {
return @[[KCURLProtocol class]];
//如果还有其他的监控protocol,也可以在这里加进去
}