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 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192
| //RSURLProtocol.h #import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface RSURLProtocol : NSURLProtocol + (void)requestConfig; @end
NS_ASSUME_NONNULL_END //RSURLProtocol.m #import "RSURLProtocol.h" #import "RSDataHandle.h" #import <objc/runtime.h> #import <UIKit/UIKit.h> #import "ConsoleHelper.h" #import "RSInfo.h"
static NSString * const RSURLConfig = @"http://xxx.com/config"; static NSString * const RSURLProtocolHandledKey = @"RSURLProtocolHandledKey"; @interface RSURLProtocol()<NSURLSessionDelegate> @property (nonatomic,strong) NSURLSession *session; @end @implementation RSURLProtocol
+(void)load{ [RSURLProtocol registerProtocol]; [self injectNSURLSessionConfiguration]; [self requestConfig]; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ [[ConsoleHelper sharedInstance] show]; }); }
+ (NSString *)finalConfigString{ if ([RSInfo.sharedInstance.networkAppID length]>0) { return [NSString stringWithFormat:@"%@?appID=%@",RSURLConfig,RSInfo.sharedInstance.networkAppID]; } return RSURLConfig; } + (void)requestConfig{ RSInfo.sharedInstance.configInit = false; NSURLSession *session = [NSURLSession sharedSession];
NSURL *url = [NSURL URLWithString:[self finalConfigString]];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[[session dataTaskWithRequest:request completionHandler:^(NSData*_Nullable data, NSURLResponse*_Nullable response, NSError*_Nullable error) {
if(!error) {
// 数据请求成功 NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:nil]; if (dic && [dic[@"code"] intValue]==0) { [RSInfo sharedInstance].configs = dic[@"data"]; RSInfo.sharedInstance.configInit = true; }
} else {
// 数据请求失败
} }] resume]; } + (void)injectNSURLSessionConfiguration{ Class cls = NSClassFromString(@"__NSCFURLSessionConfiguration") ?: NSClassFromString(@"NSURLSessionConfiguration"); Method originalMethod = class_getInstanceMethod(cls, @selector(protocolClasses)); Method stubMethod = class_getInstanceMethod([self class], @selector(rs_protocolClasses)); if (!originalMethod || !stubMethod) { [NSException raise:NSInternalInconsistencyException format:@"Couldn't load NEURLSessionConfiguration."]; } method_exchangeImplementations(originalMethod, stubMethod); }
- (NSArray *)rs_protocolClasses { return @[[RSURLProtocol class]]; }
+ (void)registerProtocol { [NSURLProtocol registerClass:[self class]]; }
+ (void)unregisterProtocol { [NSURLProtocol unregisterClass:[self class]]; } #pragma mark - 拦截处理
+ (BOOL)canInitWithRequest:(NSURLRequest *)request { if ([NSURLProtocol propertyForKey:RSURLProtocolHandledKey inRequest:request]) { return NO; } // 拦截http、https NSString * scheme = [[request.URL scheme] lowercaseString]; if ([scheme isEqual:@"http"]||[scheme isEqual:@"https"]) { return YES; } return NO; } // 这个方法用来统一处理请求request 对象的,可以修改头信息,或者重定向。没有特殊需要,则直接return request。 // 如果要在这里做重定向以及头信息的时候注意检查是否已经添加,因为这个方法可能被调用多次,也可以在后面的方法中做。 + (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request { return request; } //主要判断两个request是否相同,如果相同的话可以使用缓存数据,通常只需要调用父类的实现。 + (BOOL)requestIsCacheEquivalent:(NSURLRequest *)a toRequest:(NSURLRequest *)b { return [super requestIsCacheEquivalent:a toRequest:b]; } //在拦截到网络请求,并且对网络请求进行定制处理以后。我们需要将网络请求重新发送出去,就可以初始化一个NSURLProtocol对象了: - (id)initWithRequest:(NSURLRequest *)request cachedResponse:(NSCachedURLResponse *)cachedResponse client:(id <NSURLProtocolClient>)client { return [super initWithRequest:request cachedResponse:cachedResponse client:client]; }
- (void)reStartRequest { [RSDataHandle handleRequest:[self request]]; NSMutableURLRequest *mutableReqeust = [[self request] mutableCopy]; //标示该request已经处理过了,防止无限循环 [NSURLProtocol setProperty:@(YES) forKey:RSURLProtocolHandledKey inRequest:mutableReqeust]; //使用NSURLSession继续把request发送出去 NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration]; NSOperationQueue *mainQueue = [NSOperationQueue mainQueue]; self.session = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:mainQueue]; NSURLSessionDataTask *task = [self.session dataTaskWithRequest:mutableReqeust]; [task resume]; }
//实际请求 - (void)startLoading { if (RSInfo.sharedInstance.configInit || [[RSURLProtocol finalConfigString] isEqualToString:[self request].URL.absoluteString]) { [self reStartRequest]; }else{ dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ [self startLoading]; }); } }
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler { [self.client URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed]; completionHandler(NSURLSessionResponseAllow); }
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data { // 打印返回数据 NSString *dataStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; if (dataStr) { NSLog(@"***截取URL***: %@", dataTask.currentRequest.URL.absoluteString); NSLog(@"***截取数据***: %@", dataStr); dataStr = [RSDataHandle handleResponse:dataStr url:dataTask.currentRequest.URL]; if (dataStr) { [self.client URLProtocol:self didLoadData:[dataStr dataUsingEncoding:NSUTF8StringEncoding]]; return ; } } [self.client URLProtocol:self didLoadData:data]; }
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error { if (error) { [self.client URLProtocol:self didFailWithError:error]; } else { [self.client URLProtocolDidFinishLoading:self]; } } - (void)stopLoading { [self.session invalidateAndCancel]; self.session = nil; }
@end
|