国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統(tǒng) > iOS > 正文

詳解如何攔截iOS所有網(wǎng)絡(luò)請求

2020-07-26 02:26:51
字體:
供稿:網(wǎng)友

背景

最近在研究iOS無埋點統(tǒng)計技術(shù),我們的統(tǒng)計SDK主要分兩部分:點擊事件和網(wǎng)絡(luò)請求。統(tǒng)計所有的點擊事件是采用Method Swizzling實現(xiàn)的,可以做到使用中不需要一行代碼實現(xiàn)統(tǒng)計所有事件,具體細(xì)節(jié)將來我會專門抽幾篇文章介紹。

今天主要說說如何統(tǒng)計APP中的所有網(wǎng)絡(luò)請求。公司網(wǎng)絡(luò)請求如果不是靜態(tài)庫或者框架,很容易想到在網(wǎng)絡(luò)請求發(fā)送和返回時添加統(tǒng)計的代碼。如何在不修改原來代碼(或者修改最少)的基礎(chǔ)上攔截所有的請求呢,能不能從系統(tǒng)層面上攔截回調(diào)呢?答案是肯定的,蘋果有一個黑魔法NSURLProtocol

介紹

NSURLProtocol是iOS URL Loading System中的一部分,看起來像是一個協(xié)議,但其實這是一個類,而且必須使用該類的子類,并且需要被注冊。先看看他在URL Loading System中的位置:


使用場景

不管是UIWebView還是URLSession還是第三方的AFNetWorkongAlamofire或者SDWebImage他們都是基于URLSession或者NSURLConnection來實現(xiàn)的,因此可以通過NSURLProtocol做自定義操作。

  1. 重定向網(wǎng)絡(luò)請求
  2. 攔截網(wǎng)絡(luò)加載,采用本地緩存
  3. 修改Request信息
  4. 自定義返回結(jié)果
  5. 對請求進(jìn)行HTTPDNS解析,動態(tài)設(shè)置Host,解決不同網(wǎng)絡(luò)下客戶端不能訪問的情況

實現(xiàn)

首先要繼承NSURLProtocol創(chuàng)建自定義的類,然后重寫startLoading、stopLoading添加我們的統(tǒng)計代碼就可以了:

static NSString * const hasInitKey = @"LLMarkerProtocolKey";@interface LLMarkerURLProtocol : NSURLProtocol@end

子類實現(xiàn)的NSURLProtocol方法:

1.0 +(BOOL)canInitWithRequest:(NSURLRequest *)request;子類是否能響應(yīng)該請求。

+(BOOL)canInitWithRequest:(NSURLRequest *)request{ if ([NSURLProtocol propertyForKey:hasInitKey inRequest:request]) {  return NO; } return YES;}

2.0  +(NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request;自定義網(wǎng)絡(luò)請求,如果不需要處理直接返回request。

+(NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request{ return request;}

3.0  -(void)startLoading 開始網(wǎng)絡(luò)請求,需要在該方法中發(fā)起一個請求,對于NSURLConnection來說,就是創(chuàng)建一個NSURLConnection,對于NSURLSession,就是發(fā)起一個NSURLSessionTask 。一般下載前需要設(shè)置該請求正在進(jìn)行下載,防止多次下載的情況發(fā)生。

-(void)startLoading{ NSMutableURLRequest *mutableReqeust = [[self request] mutableCopy]; //做下標(biāo)記,防止遞歸調(diào)用 [NSURLProtocol setProperty:@YES forKey:hasInitKey inRequest:mutableReqeust]; self.connection = [NSURLConnection connectionWithRequest:mutableReqeust delegate:self];}

4.0  -(void)stopLoading 停止相應(yīng)請求,清空請求Connection 或Task。

-(void)stopLoading{ [self.connection cancel];}

5.0 實現(xiàn)NSURLConnectionDelegateNSURLConnectionDataDelegate或者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;}

攔截第三方網(wǎng)絡(luò)庫方法就是讓第三方使用我們這個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進(jìn)行網(wǎng)絡(luò)請求

let manager = LLSessionManger.sharedManagermanager.request("https://httpbin.org/get").responseJSON { (response) in if let JSON = response.result.value {  print("JSON: /(JSON)") }}

注意:AFNetWorking、SDWebimage等第三方庫的修改和Alamofire類似,找到使用NSURLSessionConfiguration的地方,換成LLMarkerURLProtocol的defaultSessionConfiguration就可以了。

看到這你可能發(fā)現(xiàn),如果使用Alamofire進(jìn)行網(wǎng)絡(luò)請求,我們還是修改了原來的代碼,下篇文章單獨介紹如何不修改原來代碼,通過注冊Alamofire通知方式,攔截Alamofire的網(wǎng)絡(luò)請求。

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持武林網(wǎng)。

發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 深水埗区| 清水河县| 宣恩县| 罗源县| 佛学| 邯郸市| 蓝田县| 阳城县| 富平县| 镇远县| 前郭尔| 长阳| 永胜县| 岑巩县| 武义县| 屯留县| 郸城县| 多伦县| 开阳县| 彩票| 凤阳县| 佛坪县| 从化市| 台东市| 诸暨市| 腾冲县| 文安县| 徐汇区| 灵山县| 治多县| 苗栗县| 嘉义市| 大冶市| 湖口县| 石嘴山市| 福安市| 利津县| 剑阁县| SHOW| 三穗县| 会同县|