iOS實際網絡檢測框架RealReachability
來自: http://www.henishuo.com/ios-realreachability/
背景
網絡連接狀態檢測對于我們的iOS app開發來說是一個非常通用的需求。為了更好的用戶體驗,我們會在無網絡時展現本地或者緩存的內容,并對用戶進行合適的提示。但事實上,當前iOS開發者們普遍使用的網絡檢測框架,實際上都無法幫助我們檢測真正的網絡連接狀態;它們所能檢測的只是本地連接狀態。 本地連接狀態和實際網絡連接狀態不一致的“偽連接”情況包括但不限于如下場景:
- 現在很流行的公用wifi,需要網頁鑒權,鑒權之前無法上網,但本地連接已經建立;
- 存在了本地網絡連接,但信號很差,實際無法連接到服務器;
- iOS連接的路由設備本身沒有連接外網。
很多國內外的網友關于此問題早有提問和吐槽,比如:
- 如何判斷設備是否真正連上互聯網?而不是只有網絡連接
- [Reachability reachabilityWithHostName:]完全沒用!
- 國外網友對Reachability庫缺陷在github上的提問
為了著手解決此類問題,筆者希望就此打造一個通用、簡單、可靠并且能檢測實際網絡連接狀態的框架,從而幫助提升app在上述場景下的用戶體驗;這就是 RealReachability 的由來。
iOS下的網絡檢測方案
- 從 蘋果示例代碼 衍生而來的各類變種,是被開發者們使用最多的;即各類reachability命名相關的框架。其中最負盛名的當屬 tonymillion的Reachability 。其基礎代碼來源于蘋果,開發者們對其進行了擴展和語法上的支持(比如block回調等),使其更易于使用。
- AFNetworking框架中也提供了AFNetworkReachabilityManager,很多使用AFNetworking的小伙伴們會順帶使用該組件來進行網絡檢測。其代碼基于蘋果的 SCNetworkReachability API ,封裝結構清晰,易于使用,且包含在AFNetworking中,也受到大家的喜愛。
- 一些app本身包含了例如xmpp之類的功能,此類實現通常會向連接的服務器定時發送心跳包,主要用于長連接的保活和斷線處理;如果客戶端沒有收到server端回傳的包,那么我們可以認為實際網絡連接已經失效。sip協議也有類似的保活實現,定時間隔都是可配置的。基于server端連接穩定的前提,我們也可以利用這類心跳保活的機制間接達到實際網絡狀態檢測的效果。
- 各種網絡請求的超時。在上述偽連接的場景下,用戶觸發的http請求的通常結果就是超時,該時間一般不短于30秒。理論上說我們可以根據網絡請求的結果來標識實際的網絡狀態,但這樣做帶來了實現上的耦合性(網絡檢測本應該是獨立的功能模塊),同時超時時間的等待也不利于打造一個很好的用戶體驗。
RealReachability簡單介紹
RealReachability是筆者1個月之前發布到github的開源庫,項目地址如下: https://github.com/dustturtle/RealReachability。
短短1個月時間收獲了幾百個star,最近還上了github的 oc板塊趨勢排行榜 ,開發者們對此框架的熱情完全出乎了筆者的意料;這也正說明此框架抓住了開發者們的痛點。
此框架開發的初衷來源于項目實際需求,離線模式對網絡連接狀態的要求比較苛刻,且實際場景經常會遇到“偽連接”的情況,項目中所使用的Reachability面對此場景力不從心。多方研究后引入了ping能力(此方案流量開銷最小,也最簡單),實現了簡單的實際網絡連接監測;后面將ping的能力和本地網絡檢測有機的結合,并且在實時性和開銷上達成了一個平衡,不斷提煉和優化,于是有了這個框架。
可以告訴大家的是,這個框架在appstore上架應用中已經經受了考驗,且經過了長時間的測試,可以放心使用;目前也已經有很多開發者朋友們在其app中使用了我們的框架(讓筆者略感自豪的是,他們來自世界各地!)。
RealReachability的實現原理
RealReachability的架構
RealReachability主要包含3大模塊:connection、ping、FSM;
其中Ping模塊通過對同樣是蘋果提供的ping樣例代碼進行了封裝,connection模塊實現了基于SCNetworkReachability的本地狀態檢測,FSM模塊是有限狀態機。
通過FSM的狀態管理控制connection模塊和Ping模塊協同工作,剔除了重復的狀態變化,并通過可配置的定時策略等業務邏輯優化,權衡了實時性和開銷,最終得到了我們的實現。PS:其中connection模塊和ping模塊也可獨立使用,分別提供本地網絡檢測和ping的能力。
感興趣的讀者也可以嘗試(調用方式請參考RealReachability開源代碼)。
RealReachability的應用范圍和場景
我們致力于打造一個打造一個通用、簡單、可靠并且能檢測實際網絡連接狀態的框架,從而幫助app開發者們在各種偽連接的場景下,也能夠檢測出網絡真實的可達性,從而優化app的體驗;現代架構的移動app大部分是胖客戶端,即使離開了網絡,也能提供很大一部分功能。RealReachability的能力也限于此。比如網速檢測、個人熱點信息檢查等功能,不是此框架的設計目標,也超出了其能力范圍。
RealReachability的開銷
localconnection是基于本地的檢測,因此其帶來的開銷可以忽略;ping模塊的單次ICMP探測包大小僅為64字節(包含包頭部),探測的頻率默認為2分鐘1次,對于客戶端來說1小時的應用前臺運行僅額外消耗2kb的流量,完全忽略不計;對于server端來說,如此低頻率、低流量的分布式ICMP包,也不會帶來壓力:對比正常動輒幾十kb甚至更多大小的請求,可以說是九牛一毛。
RealReachability基礎使用
RealReachability集成和依賴
- 最簡便的集成方法當屬pod: pod ‘RealReachability’;當前的pod穩定版本版本號為1.1.1。
- 手動集成:將RealReachability文件夾加入到工程即可。
- 依賴:Xcode5.0+,支持ARC, iOS6+.項目需要引入SystemConfiguration.framework.
使用介紹
其接口的設計和調用方法和Reachability非常相似,大家可以無縫上手,非常方便。 開啟網絡監聽:
[GLobalRealReachability startNotifier]; [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(networkChanged:) name:kRealReachabilityChangedNotification object:nil];
關閉網絡監聽:
[GLobalRealReachability stopNotifier];
回調代碼示例:
- (void)networkChanged:(NSNotification *)notification { RealReachability *reachability = (RealReachability *)notification.object; ReachabilityStatus status = [reachabilitycurrentReachabilityStatus]; NSLog(@"currentStatus:%@",@(status)); }
查詢當前實際網絡連接狀態:
ReachabilityStatus status = [reachabilitycurrentReachabilityStatus];
RealReachability進階使用(可選)
手動觸發實時網絡狀態查詢,可以在block回調中處理自己的業務(特別是網絡請求操作),此接口的block會被異步調用。代碼示例:
[GLobalRealReachabilityreachabilityWithBlock:^(ReachabilityStatus status) { switch (status) { caseRealStatusNotReachable: { // case NotReachable handler break; } caseRealStatusViaWiFi: { // case WiFi handler break; } caseRealStatusViaWWAN: { // case WWAN handler break; } default: break; } }];
手動設置目標host地址(ping探測的目標地址):
GLobalRealReachability.hostForPing = @"www.baidu.com";
注意:需要確保該host地址可以被ping探測到。此操作為可選,默認的目標host地址為www.baidu.com。
手動設置自動探測間隔(autoCheckInterval,單位為分鐘):
GLobalRealReachability.autoCheckInterval = 3.0f;
注意:此處根據應用的實時性要求來設置自動探測的間隔,實時性要求較高時可適當調低此參數,但不建議設置為1.0以下。
結束語
希望這個框架能夠幫助到大家的iOS開發! 遇到任何疑問或者使用上的問題,都可以聯系我(管振緯/游族iOS高級工程師),期待與您交流iOS開發技術: [email protected]
對此框架我也會持續進行維護和優化,更希望感興趣的朋友可以到github上pull request! 開源有你更精彩!
源代碼
作者介紹
本文原作者:管振緯/游族iOS高級工程師
作者QQ群:494669518
原作者 管振緯 授權標哥的技術博客發表本篇博文。
參考鏈接
- https://github.com/dustturtle/RealReachability
- https://developer.apple.com/library/ios/samplecode/Reachability/Introduction/Intro.html
- https://developer.apple.com/library/mac/documentation/SystemConfiguration/Reference/SCNetworkReachabilityRef/#//apple_ref/doc/uid/TP40007260-CH101-SW4
- https://github.com/tonymillion/Reachability
- http://www.cocoachina.com/bbs/read.php?tid=283498
- https://github.com/tonymillion/Reachability/issues/91
- http://www.cocoachina.com/bbs/read.php?tid=40989
- http://rainbird.blog.51cto.com/211214/695979
關注我
關注 | 賬號 | 備注 |
---|---|---|
Swift/ObjC技術群一 | 324400294 | 群一若已滿,請申請群二 |
Swift/ObjC技術群二 | 494669518 | 群二若已滿,請申請群三 |
Swift/ObjC技術群三 | 461252383 | 群三若已滿,會有提示信息 |
關注微信公眾號 | iOSDevShares | 關注微信公眾號,會定期地推送好文章 |
關注新浪微博賬號 | 標哥Jacky | 關注微博,每次發布文章都會分享到新浪微博 |
關注標哥的GitHub | CoderJackyHuang | 這里有很多的Demo和開源組件 |
關于我 | 進一步了解標哥 | 如果覺得文章對您很有幫助,可捐助我! |
版權聲明:本文為【標哥的技術博客】原創出品,歡迎轉載,轉載時請注明出處!
</div>