iOS端網(wǎng)絡(luò)監(jiān)控思路及實(shí)現(xiàn)

一、背景

網(wǎng)絡(luò)監(jiān)控主要用于監(jiān)控應(yīng)用的網(wǎng)絡(luò)請(qǐng)求,獲取網(wǎng)絡(luò)請(qǐng)求相關(guān)的性能參數(shù),方便開(kāi)發(fā)、測(cè)試、產(chǎn)品等人員對(duì)應(yīng)用進(jìn)行分析。

二、指標(biāo)

一般監(jiān)控的指標(biāo)主要有:成功率、狀態(tài)碼、流量、網(wǎng)絡(luò)響應(yīng)時(shí)間、HTTP與HTTPS的 DNS 解析、TCP握手、SSL握手(HTTP除外)、首包時(shí)間等。

三、思路

iOS中常見(jiàn)的網(wǎng)絡(luò)請(qǐng)求

蘋果官方:

系統(tǒng)網(wǎng)絡(luò)請(qǐng)求框架

第三方框架:

第三方網(wǎng)絡(luò)請(qǐng)求框架

NSURLConnection在iOS9之后,已經(jīng)被蘋果廢棄,取而代之的是iOS7之后出現(xiàn)的NSURLSession。

現(xiàn)在各方案的使用率大概如下:

網(wǎng)絡(luò)框架使用率

從圖中可以看出,現(xiàn)在iOS中使用得最多的網(wǎng)絡(luò)請(qǐng)求依次是AFNetworking、NSURLSession、NSURLConnection。

iOS網(wǎng)絡(luò)框架層級(jí)關(guān)系如下所示:

網(wǎng)絡(luò)框架層級(jí)關(guān)系

從圖中可以看出,iOS網(wǎng)絡(luò)框架由4層組成。最底層的即是系統(tǒng)層的BSD Sockets。中間的框架層又分為兩級(jí),CFNetwork是純C語(yǔ)言實(shí)現(xiàn)的,NSURLConnection、NSURLSession、UIWebView是用Objective-C實(shí)現(xiàn)的,而且都調(diào)用的CFNetwork。最上面應(yīng)用層的AFNetworking是第三方框架,是基于NSURLConnection和NSURLSession實(shí)現(xiàn)的。

iOS AOP編程主要方式

  • Method Swizzling

每一個(gè)NSObject類都包含一個(gè)isa指針,指向objc_class結(jié)構(gòu)體,而每一個(gè)objc_class結(jié)構(gòu)體又包含一個(gè)methodLists指針,指向objc_method_list結(jié)構(gòu)體數(shù)組,在objc_method_list里又包含一個(gè)objc_method結(jié)構(gòu)體成員,且每一個(gè)objc_method包含一個(gè)method_imp指針,指向方法實(shí)現(xiàn)。因此,只要能修改method_imp的值,就能替換原有的實(shí)現(xiàn)。

  • Proxy

在Objective-C里,NSProxy是除NSObject外唯一的根類。NSProxy是一個(gè)實(shí)現(xiàn)了NSObject協(xié)議的抽象類,它的正常運(yùn)作需要子類override-methodSignatureForSelector:方法為sel提供方法簽名,以及-forwardInvocation:方法來(lái)完成調(diào)用的轉(zhuǎn)發(fā)。使用Proxy來(lái)注入NSURLConnection、NSURLSession等對(duì)delegate的回調(diào)。具體來(lái)說(shuō),在delegate proxy收到消息時(shí),如果不是目標(biāo)協(xié)議方法,則通過(guò)消息轉(zhuǎn)發(fā)機(jī)制,轉(zhuǎn)發(fā)給原delegate;如果是目標(biāo)協(xié)議方法,則直接調(diào)用proxy實(shí)現(xiàn),在proxy實(shí)現(xiàn)中委托調(diào)用原delegate;此外,多數(shù)協(xié)議和協(xié)議方法都是可選的,因此,在proxy的實(shí)現(xiàn)中需要實(shí)現(xiàn)-conformsToProtocol:和-respondsToSelector:方法來(lái)聲明proxy額外加入的協(xié)議和方法。

  • FishHook

使用fishhook來(lái)替換動(dòng)態(tài)鏈接庫(kù)中的C函數(shù)實(shí)現(xiàn),具體來(lái)說(shuō)是CFNetwork和CoreFoundation中的相關(guān)函數(shù)。在程序運(yùn)行時(shí),動(dòng)態(tài)鏈接的C函數(shù)dynamic(...)地址記錄在DATA segment下的la_symbol_ptr中;初始時(shí),程序只知道dynamic函數(shù)的符號(hào)名而不知道函數(shù)的實(shí)現(xiàn)地址;首次調(diào)用時(shí),程序通過(guò)TEXT segment中的stub_helper取得綁定信息,通過(guò)dyld_stub_binder來(lái)更新la_symbol_ptr中的符號(hào)實(shí)現(xiàn)地址;這樣,再次調(diào)用時(shí),就可以通過(guò)la_symbol_ptr直接找到dynamic函數(shù)的實(shí)現(xiàn);如果我們需要替換dynamic函數(shù)的實(shí)現(xiàn),只需要修改_la_symbol_ptr即可。

  • NSURLProtocol

NSURLProtocol是iOS中URL Loading System的一部分。如果開(kāi)發(fā)者自定義的一個(gè)NSURLProtocol并且注冊(cè)到app中,那么在這個(gè)自定義的NSURLProtocol中我們可以攔截UIWebView,基于系統(tǒng)的NSURLConnection或者NSURLSession進(jìn)行封裝的網(wǎng)絡(luò)請(qǐng)求,然后做到自定義的response返回。

四、實(shí)現(xiàn)

根據(jù)前面的分析和比較,可以得出網(wǎng)絡(luò)監(jiān)控的實(shí)現(xiàn)方案。

監(jiān)聽(tīng)的網(wǎng)絡(luò)框架

可能需要監(jiān)聽(tīng)的網(wǎng)絡(luò)框架包括:AFNetworking、NSURLConnection、NSURLSession、CFNetwork。

首先,由于CFNetwork位于較低層,在iOS10之后,很多方法hook不了,因此放棄對(duì)CFNetwork的監(jiān)控。

其次,AFNetworking位于最上層的應(yīng)用層,是基于NSURLConnection、NSURLSession實(shí)現(xiàn)的,因此只要監(jiān)控了NSURLConnection、NSURLSession,就相當(dāng)于監(jiān)控了AFNetworking。因此,選擇監(jiān)控的網(wǎng)絡(luò)框架為NSURLSession和NSURLConnection。

使用的AOP方式

因?yàn)镹SURLConnection和NSURLSession使用的是Objective-C實(shí)現(xiàn)的,所以用不上fishhook,但是要用到Method Swizzling、Proxy以及URLProtocol。

對(duì)于網(wǎng)絡(luò)時(shí)間的監(jiān)控

單獨(dú)把網(wǎng)絡(luò)時(shí)間的監(jiān)控提出來(lái),是因?yàn)榫W(wǎng)絡(luò)時(shí)間監(jiān)控稍微復(fù)雜。因?yàn)樵诟邔泳W(wǎng)絡(luò)框架中,對(duì)于各階段執(zhí)行的時(shí)間節(jié)點(diǎn)都被封裝起來(lái)了。需要到BSDSocket級(jí)別才能監(jiān)控到這些時(shí)間。但是經(jīng)過(guò)實(shí)驗(yàn),在iOS10之后,可能是系統(tǒng)進(jìn)行了加固,BSDSocket中有些方法沒(méi)有辦法進(jìn)行hook了。在iOS10之后,NSURLSession中有API提供了對(duì)應(yīng)的時(shí)間數(shù)據(jù)。

從蘋果官網(wǎng)獲取當(dāng)前蘋果手機(jī)系統(tǒng)版本使用占比如下圖所示:

iOS系統(tǒng)占比

其中iOS11約占65%,iOS10約占28%,低于iOS10的約占7%。可見(jiàn)iOS10以上系統(tǒng)占了93%,覆蓋了絕大部分用戶。因此,對(duì)于網(wǎng)絡(luò)時(shí)間的監(jiān)控,放棄hook底層BSDSocket,直接使用NSURLSession提供的數(shù)據(jù)。

需要hook的方法

對(duì)于NSURLSession:

NSURLSession需要hook的方法

對(duì)于NSURLConnection:

NSURLConnection需要hook的方法

整體設(shè)計(jì)

如下圖所示為SDK的整體結(jié)構(gòu):

SDK結(jié)構(gòu)圖

下圖為SDK整體時(shí)序:

SDK整體時(shí)序圖

五、實(shí)例

iOS端網(wǎng)絡(luò)監(jiān)控SDK及Demo見(jiàn)github地址:
https://github.com/frog78/NetworkMonitor

六、參考

http://www.cocoachina.com/ios/20170302/18815.html
http://www.cocoachina.com/ios/20170629/19680.html
http://www.cocoachina.com/ios/20170630/19683.html
https://juejin.im/post/5b1602906fb9a01e3542f08c

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 1、通過(guò)CocoaPods安裝項(xiàng)目名稱項(xiàng)目信息 AFNetworking網(wǎng)絡(luò)請(qǐng)求組件 FMDB本地?cái)?shù)據(jù)庫(kù)組件 SD...
    陽(yáng)明AI閱讀 16,236評(píng)論 3 119
  • 如果你認(rèn)為人死后什么都不記得,那就錯(cuò)了。我死了,生前的一切仍歷歷在目,恍如昨日。 我記得我待過(guò)的形形色色的地方——...
    楊小帥他爹閱讀 453評(píng)論 0 1
  • 前陣子看了很多日本寫的企業(yè)文化的書,對(duì)我有很大的影響。當(dāng)時(shí)我就想,中國(guó)的高速發(fā)展,似乎每個(gè)人都在講創(chuàng)新,講理念,但...
    李三喵閱讀 409評(píng)論 1 0
  • 凈―― 純―― 美―― 耀―― 旅行的旅途中,看到這樣純凈的天空,再煩躁的心情也會(huì)變得安靜,變得愜意――
    44先生閱讀 228評(píng)論 0 1
  • 中午回家,發(fā)現(xiàn)手袋里邊很香,原來(lái)是早上摘了茉莉花,把茉莉花送給了林記和媽媽以后,只留下一個(gè)空空如也的保鮮袋,香味就...
    文曉玲閱讀 199評(píng)論 3 4

友情鏈接更多精彩內(nèi)容