iOS完美的網(wǎng)絡(luò)狀態(tài)判斷工具

大多數(shù)App都嚴(yán)重依賴于網(wǎng)絡(luò),一款用戶體驗(yàn)良好的的app是必須要考慮網(wǎng)絡(luò)狀態(tài)變化的.iOS下一般使用Reachability這個(gè)類來(lái)檢測(cè)網(wǎng)絡(luò)的變化.

Reachability

這個(gè)是蘋果開發(fā)文檔里面的一個(gè)類,官方寫的,用來(lái)判斷網(wǎng)絡(luò)的變化,包括無(wú)網(wǎng)絡(luò),wifi,和蜂窩三種情況.官方地址:點(diǎn)我查看.Reachability類實(shí)際上是蘋果公司對(duì)SCNetworkReachability API的封裝,使用方法比較簡(jiǎn)單,這里不再介紹.說(shuō)說(shuō)它的優(yōu)缺點(diǎn):

  • 優(yōu)點(diǎn)
    • 使用簡(jiǎn)單,只有一個(gè)類,官方還有Demo,容易上手
    • 靈敏度高,基本網(wǎng)絡(luò)一有變化,基本馬上就能判斷出來(lái)
    • 能夠判斷有網(wǎng)狀態(tài)的切換比如2G/3G/4G/wifi的實(shí)時(shí)切換
  • 缺點(diǎn)
    • 不能判斷蜂窩移動(dòng)網(wǎng)的具體類型,如3G,4G
    • 不能判斷路由器本身是否能聯(lián)網(wǎng)
    • 能否連接到指定服務(wù)器,比如國(guó)內(nèi)訪問(wèn)墻外的服務(wù)器
    • 有網(wǎng),但是信號(hào)很差,網(wǎng)速很慢,跟沒(méi)網(wǎng)一樣.這時(shí)候應(yīng)該認(rèn)為無(wú)網(wǎng).

解決方案

事實(shí)上Reachability已經(jīng)很好了,但是實(shí)際上客戶端到達(dá)服務(wù)器需要很多道"關(guān)卡",例如路由器,電信服務(wù)器,防火墻等.其實(shí)說(shuō)白了就是解決一個(gè)問(wèn)題:客戶端是否能夠成功訪問(wèn)服務(wù)器.這里介紹另外一個(gè)官方的類:SimplePing點(diǎn)我查看.

SimplePing

SimplePing也是官方文檔的一個(gè)類,目的是ping服務(wù)器,可以判斷客戶端是否可以連接到指定服務(wù)器.ping 類似于心跳包功能,隔一段時(shí)間就ping下服務(wù)器,看是否暢通無(wú)阻.因此ping不可能做到及時(shí)判斷網(wǎng)絡(luò)變化,會(huì)有一定的延遲.可能大家已經(jīng)猜到了我的思路,沒(méi)錯(cuò),把他們兩個(gè)合在一起.下面說(shuō)說(shuō)我的思路:

  • 首先利用Reachability判斷設(shè)備是否聯(lián)網(wǎng),至于能不能連接到服務(wù)器用ping來(lái)檢查
  • 如果Reachability判斷為有網(wǎng),并且ping也判斷為有網(wǎng),那么表示真的有網(wǎng),否則就是沒(méi)網(wǎng).
  • ping 雖然能夠判斷客戶端到服務(wù)器是否暢通,但是由于網(wǎng)絡(luò)抖動(dòng)或者網(wǎng)絡(luò)很弱等原因,可能出現(xiàn)ping失敗的情況,解決方案就是加上失敗次數(shù)限制,超過(guò)限制就認(rèn)為斷網(wǎng)了.
  • 2/3/4G切換的時(shí)候,Reachability雖然檢測(cè)到了網(wǎng)絡(luò)變化,但是類型還是蜂窩移動(dòng),不能給出具體的網(wǎng)絡(luò)類型.這里可以通過(guò)獲取狀態(tài)欄上的屬性來(lái)判斷.
- (SGNetworkStatus)netWorkDetailStatus{
  UIApplication *app = [UIApplication sharedApplication];
  UIView *statusBar = [app valueForKeyPath:@"statusBar"];
  UIView *foregroundView = [statusBar valueForKeyPath:@"foregroundView"];
  
  UIView *networkView = nil;
  
  for (UIView *childView in foregroundView.subviews) {
      if ([childView isKindOfClass:NSClassFromString(@"UIStatusBarDataNetworkItemView")]) {
          networkView = childView;
      }
  }
  
  SGNetworkStatus status = SGNetworkStatusNone;
  
  if (networkView) {
      int netType = [[networkView valueForKeyPath:@"dataNetworkType"]intValue];
      switch (netType) {
          case 0:
              status = SGNetworkStatusNone;
              break;
          case 1://實(shí)際上是2G
              status = SGNetworkStatusUkonow;
              break;
          case 2:
              status = SGNetworkStatus3G;
              break;
          case 3:
              status = SGNetworkStatus4G;
              break;
          case 5:
              status = SGNetworkStatusWifi;
              break;
          default:
              status = SGNetworkStatusUkonow;
              break;
      }
  }
  return status;
}

可喜的是,即使隱藏了狀態(tài)欄,判斷依然有效!

其他細(xì)節(jié)

  • 默認(rèn)采用host為www.baidu.com,別噴我,不是給百度打廣告,而是因?yàn)榘俣日娴闹贿m合判斷有沒(méi)有網(wǎng),因?yàn)轫憫?yīng)真的很快.當(dāng)然也可以用自己的服務(wù)器地址,這樣更加真實(shí),萬(wàn)一你家的服務(wù)器很渣或者突然crash了也能夠完美判斷.

  • 判斷具體網(wǎng)絡(luò)類型的時(shí)候,實(shí)際上用kvc獲取了控件的私有屬性,根據(jù)網(wǎng)友的反應(yīng),沒(méi)有因此被拒的情況,因此不用擔(dān)心.如果因?yàn)檫@個(gè)原因被拒,請(qǐng)聯(lián)系我第一時(shí)間修改.

  • 支持全局通知和代理的方式.默認(rèn)全局發(fā)送通知,如果設(shè)置了delegate這個(gè)屬性,那么只有代理會(huì)收到通知,不在發(fā)送全局通知.如果想兩種方式并存,可以新建一個(gè)SGNetObserver對(duì)象.

    PS:貌似蘋果官方的原話是調(diào)用了系統(tǒng)的私有api會(huì)被拒.

  • 支持模擬器,支持IPv4,IPv6

詳細(xì)代碼在這里:https://github.com/iOSSinger/SGNetObserver,支持cocoapods,歡迎使用!

最后,如果有什么不對(duì),歡迎大家留言指正.

最后編輯于
?著作權(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)容

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