最近在研究<代码> iOS无埋点代码>统计技术,我们的<代码>统计SDK代码> 主要分两部分:点击事件和网络请求。统计所有的点击事件是采用<代码>方法纵酒代码>实现的,可以做到使用中不需要一行代码实现统计所有事件,具体细节将来我会专门抽几篇文章介绍。
今天主要说说如何统计应用中的所有网络请求。公司网络请求如果不是<代码>静态库> 代码或者<代码>框架> 代码,很容易想到在网络请求发送和返回时添加统计的代码。如何在不修改原来代码(或者修改最少)的基础上拦截所有的请求呢,能不能从系统层面上拦截回调呢?答案是肯定的,苹果有一个黑魔法<代码> NSURLProtocol> 代码。
NSURLProtocol是iOS URL加载系统中的一部分,看起来像是一个协议,但其实这是一个类,而且必须使用该类的子类,并且需要被注册。先看看他在URL加载系统中的位置:
静态NSString * const hasInitKey=@“LLMarkerProtocolKey”; @ interface LLMarkerURLProtocol: NSURLProtocol @end
子类实现的NSURLProtocol方法:
1.0 <代码> + (BOOL) canInitWithRequest: (NSURLRequest *)请求> 代码;子类是否能响应该请求。
+ (BOOL) canInitWithRequest:请求(NSURLRequest *) { 如果([NSURLProtocol propertyForKey: hasInitKey inRequest:请求)){ 返回NO; } 返回YES; } >之前2.0,<代码> + (NSURLRequest *) canonicalRequestForRequest: (NSURLRequest *)请求> 代码;自定义网络请求,如果不需要处理直接返回请求。
+ (NSURLRequest *) canonicalRequestForRequest:请求(NSURLRequest *) { 返回请求; } >之前3.0 <代码>,- (void) startload 代码>开始网络请求,需要在该方法中发起一个请求,对于NSURLConnection来说,就是创建一个NSURLConnection,对于NSURLSession,就是发起一个NSURLSessionTask。一般下载前需要设置该请求正在进行下载,防止多次下载的情况发生。
- (void) startload { NSMutableURLRequest * mutableReqeust=[[自我要求]mutableCopy];//做下标记,防止递归调用 [NSURLProtocol setProperty: @YES forKey: hasInitKey inRequest: mutableReqeust); 自我。连接=(NSURLConnection connectionWithRequest: mutableReqeust委托:自我); } >之前4.0, <代码> - - - - - - (void) stopLoading 代码>停止相应请求,清空请求连接或任务。
- (void) stopLoading { (自我。连接取消); } >之前5.0实现<代码> NSURLConnectionDelegate 代码>,<代码> NSURLConnectionDataDelegate> 代码或者<代码> NSURLSessionTaskDelegate> 代码。
# pragma马克- NSURLConnectionDelegate - (void)连接:(NSURLConnection *)连接didFailWithError:错误(NSError *) { (自我。客户端URLProtocol:自我didFailWithError:错误); } # pragma马克- NSURLConnectionDataDelegate - (void)连接:(NSURLConnection *)连接didReceiveResponse: (NSURLResponse *)反应 { 自我。responseData=中[[NSMutableData alloc] init); (自我。客户端URLProtocol:自我didReceiveResponse:响应cacheStoragePolicy: NSURLCacheStorageNotAllowed]; } - (void)连接:连接(NSURLConnection *) didReceiveData:数据(NSData *) { (自我。responseData方法中:数据); (自我。客户端URLProtocol:自我didLoadData:数据); } - (void) connectionDidFinishLoading:连接(NSURLConnection *) { (自我。客户端URLProtocolDidFinishLoading:自我); }详解如何拦截iOS所有网络请求