网络

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,也可以在这里加进去

}

原文地址:https://www.cnblogs.com/coolcold/p/12258798.html