欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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

 更新時(shí)間:2018年06月08日 10:41:22   作者:LvesLi  
這篇文章主要介紹了詳解如何攔截iOS所有網(wǎng)絡(luò)請(qǐng)求,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧

背景

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

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

介紹

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


使用場(chǎng)景

不管是UIWebView還是URLSession還是第三方的AFNetWorkong、Alamofire或者SDWebImage他們都是基于URLSession或者NSURLConnection來(lái)實(shí)現(xiàn)的,因此可以通過(guò)NSURLProtocol做自定義操作。

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

實(shí)現(xiàn)

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

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

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

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

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

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

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

3.0  -(void)startLoading 開始網(wǎng)絡(luò)請(qǐng)求,需要在該方法中發(fā)起一個(gè)請(qǐng)求,對(duì)于NSURLConnection來(lái)說(shuō),就是創(chuàng)建一個(gè)NSURLConnection,對(duì)于NSURLSession,就是發(fā)起一個(gè)NSURLSessionTask 。一般下載前需要設(shè)置該請(qǐng)求正在進(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)請(qǐng)求,清空請(qǐng)求Connection 或Task。

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

5.0 實(shí)現(xiàn)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中注冊(cè):

[NSURLProtocol registerClass:[LLMarkerURLProtocol class]];

這樣能攔截UIWebView和自定義的請(qǐng)求了,如果要攔截AFNetWorking、Alamofire等第三方請(qǐng)求還需要做一些修改。

二、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ò)庫(kù)方法就是讓第三方使用我們這個(gè)NSURLSessionConfiguration。因?yàn)槲覀冊(cè)谧约旱腘SURLSessionConfiguration 中的protocolClasses中注冊(cè)了自己類。

三、 下面以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ò)請(qǐng)求

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

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

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

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

最新評(píng)論