您好,登錄后才能下訂單哦!
背景
最近在研究iOS無埋點
統計技術,我們的統計SDK
主要分兩部分:點擊事件和網絡請求。統計所有的點擊事件是采用Method Swizzling
實現的,可以做到使用中不需要一行代碼實現統計所有事件,具體細節將來我會專門抽幾篇文章介紹。
今天主要說說如何統計APP中的所有網絡請求。公司網絡請求如果不是靜態庫
或者框架
,很容易想到在網絡請求發送和返回時添加統計的代碼。如何在不修改原來代碼(或者修改最少)的基礎上攔截所有的請求呢,能不能從系統層面上攔截回調呢?答案是肯定的,蘋果有一個黑魔法NSURLProtocol
。
介紹
NSURLProtocol是iOS URL Loading System中的一部分,看起來像是一個協議,但其實這是一個類,而且必須使用該類的子類,并且需要被注冊。先看看他在URL Loading System中的位置:
使用場景
不管是UIWebView還是URLSession還是第三方的AFNetWorkong
、Alamofire
或者SDWebImage
他們都是基于URLSession
或者NSURLConnection
來實現的,因此可以通過NSURLProtocol做自定義操作。
實現
首先要繼承NSURLProtocol創建自定義的類,然后重寫startLoading、stopLoading添加我們的統計代碼就可以了:
static NSString * const hasInitKey = @"LLMarkerProtocolKey"; @interface LLMarkerURLProtocol : NSURLProtocol @end
子類實現的NSURLProtocol方法:
1.0 +(BOOL)canInitWithRequest:(NSURLRequest *)request
;子類是否能響應該請求。
+(BOOL)canInitWithRequest:(NSURLRequest *)request{ if ([NSURLProtocol propertyForKey:hasInitKey inRequest:request]) { return NO; } return YES; }
2.0 +(NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request
;自定義網絡請求,如果不需要處理直接返回request。
+(NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request{ return request; }
3.0 -(void)startLoading
開始網絡請求,需要在該方法中發起一個請求,對于NSURLConnection來說,就是創建一個NSURLConnection,對于NSURLSession,就是發起一個NSURLSessionTask 。一般下載前需要設置該請求正在進行下載,防止多次下載的情況發生。
-(void)startLoading{ NSMutableURLRequest *mutableReqeust = [[self request] mutableCopy]; //做下標記,防止遞歸調用 [NSURLProtocol setProperty:@YES forKey:hasInitKey inRequest:mutableReqeust]; self.connection = [NSURLConnection connectionWithRequest:mutableReqeust delegate:self]; }
4.0 -(void)stopLoading
停止相應請求,清空請求Connection 或Task。
-(void)stopLoading{ [self.connection cancel]; }
5.0 實現NSURLConnectionDelegate
、NSURLConnectionDataDelegate
或者NSURLSessionTaskDelegate
。
#pragma mark - NSURLConnectionDelegate -(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{ [self.client URLProtocol:self didFailWithError:error]; } #pragma mark - NSURLConnectionDataDelegate - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response { self.responseData = [[NSMutableData alloc] init]; [self.client URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed]; } - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data { [self.responseData appendData:data]; [self.client URLProtocol:self didLoadData:data]; } - (void)connectionDidFinishLoading:(NSURLConnection *)connection { [self.client URLProtocolDidFinishLoading:self]; }
使用
一、在AppDelegate
中注冊:
[NSURLProtocol registerClass:[LLMarkerURLProtocol class]];
這樣能攔截UIWebView和自定義的請求了,如果要攔截AFNetWorking、Alamofire等第三方請求還需要做一些修改。
二、LLMarkerURLProtocol
中添加自定義NSURLSessionConfiguration
方法:
+ (NSURLSessionConfiguration *) defaultSessionConfiguration{ NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration]; NSMutableArray *array = [[config protocolClasses] mutableCopy]; [array insertObject:[self class] atIndex:0]; config.protocolClasses = array; return config; }
攔截第三方網絡庫方法就是讓第三方使用我們這個NSURLSessionConfiguration。因為我們在自己的NSURLSessionConfiguration 中的protocolClasses中注冊了自己類。
三、 下面以Alamofire
為例
1.0 繼承Alamofire.SessionManager
自定義SessionManager
class LLSessionManger: Alamofire.SessionManager{ public static let sharedManager: SessionManager = { let configuration = LLMarkerURLProtocol.defaultSessionConfiguration() configuration?.httpAdditionalHeaders = SessionManager.defaultHTTPHeaders let manager = Alamofire.SessionManager(configuration: configuration!) return manager }() }
2.0 使用 LLSessionManger
進行網絡請求
let manager = LLSessionManger.sharedManager manager.request("https://httpbin.org/get").responseJSON { (response) in if let JSON = response.result.value { print("JSON: \(JSON)") } }
注意:AFNetWorking、SDWebimage等第三方庫的修改和Alamofire類似,找到使用NSURLSessionConfiguration的地方,換成LLMarkerURLProtocol的defaultSessionConfiguration就可以了。
看到這你可能發現,如果使用Alamofire進行網絡請求,我們還是修改了原來的代碼,下篇文章單獨介紹如何不修改原來代碼,通過注冊Alamofire通知方式,攔截Alamofire的網絡請求。
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持億速云。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。