詳解如何攔截iOS所有網(wǎng)絡(luò)請(qǐng)求
背景
最近在研究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做自定義操作。
- 重定向網(wǎng)絡(luò)請(qǐng)求
- 攔截網(wǎng)絡(luò)加載,采用本地緩存
- 修改Request信息
- 自定義返回結(jié)果
- 對(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í)有所幫助,也希望大家多多支持腳本之家。
- iOS在頁(yè)面銷毀時(shí)如何優(yōu)雅的cancel網(wǎng)絡(luò)請(qǐng)求詳解
- node.js通過(guò)axios實(shí)現(xiàn)網(wǎng)絡(luò)請(qǐng)求的方法
- iOS當(dāng)多個(gè)網(wǎng)絡(luò)請(qǐng)求完成后執(zhí)行下一步的方法詳解
- iOS中多網(wǎng)絡(luò)請(qǐng)求的線程安全詳解
- IOS 網(wǎng)絡(luò)請(qǐng)求中設(shè)置cookie
- 詳解iOS中多個(gè)網(wǎng)絡(luò)請(qǐng)求的同步問(wèn)題總結(jié)
- IOS開發(fā)中異步網(wǎng)絡(luò)請(qǐng)求上實(shí)現(xiàn)同步邏輯
- IOS網(wǎng)絡(luò)請(qǐng)求之NSURLSession使用詳解
- iOS判斷網(wǎng)絡(luò)請(qǐng)求超時(shí)的方法
- iOS開發(fā)中不合法的網(wǎng)絡(luò)請(qǐng)求地址如何解決
相關(guān)文章
IOS 播放系統(tǒng)提示音使用總結(jié)(AudioToolbox)
這篇文章主要介紹了IOS 播放系統(tǒng)提示音使用總結(jié)(AudioToolbox)的相關(guān)資料,需要的朋友可以參考下2017-05-05iOS實(shí)現(xiàn)九宮格連線手勢(shì)解鎖
這篇文章主要為大家詳細(xì)介紹了iOS實(shí)現(xiàn)九宮格連線手勢(shì)解鎖,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-04-04IOS Xcode調(diào)試常用命令和斷點(diǎn)整理
這篇文章主要介紹了IOS Xcode調(diào)試常用命令和斷點(diǎn)整理的相關(guān)資料,這里對(duì)IOS Xcode調(diào)試常用命令進(jìn)行了總結(jié),需要的朋友可以參考下2016-12-12iOS 圖片上傳使用base64或者二進(jìn)制流上傳頭像功能
這篇文章主要介紹了iOS 圖片上傳使用base64或者二進(jìn)制流上傳頭像功能,需要的朋友可以參考下2017-09-09Swift 2.1 為 UIView 添加點(diǎn)擊事件和點(diǎn)擊效果
本文主要介紹 Swift UIView,這里給大家提供代碼示例作為參考為UIView 添加點(diǎn)擊事件和點(diǎn)擊效果,希望能幫助IOS開發(fā)的同學(xué)2016-07-07iOS內(nèi)存管理中引用計(jì)數(shù)的學(xué)習(xí)
文章給大家分享了關(guān)于iOS內(nèi)存管理中引用計(jì)數(shù)的相關(guān)知識(shí)點(diǎn),對(duì)此有需要的朋友可以跟著學(xué)習(xí)下。2018-05-05IOS?簡(jiǎn)單的本地json格式文件解析的實(shí)例詳解
這篇文章主要介紹了IOS?簡(jiǎn)單的本地json格式文件解析的實(shí)例詳解的相關(guān)資料,希望通過(guò)本文大家能夠掌握這部分內(nèi)容,需要的朋友可以參考下2017-09-09