iOS獲取網絡類型的四種方法


Reachability類只能區分WIFI和WWAN類型,卻無法區分2G網和3G網。

網上也有些方法,卻都存在Bug。

經過網上查找資料和測試,基本上總結了以下幾種方法:

 

1、使用導航欄的方式:(私有API)

代碼:

typedef enum {
    NetWorkType_None = 0,
    NetWorkType_WIFI,
    NetWorkType_2G,
    NetWorkType_3G,
} NetWorkType;

UIApplication *application = [UIApplication sharedApplication];
NSArray *subviews = [[[application valueForKey:@"statusBar"] valueForKey:@"foregroundView"]subviews];

NSNumber *dataNetWorkItemView = nil;

for (id subView in subviews) {
  if ([subView isKindOfClass:[NSClassFromString(@"UIStatusBarDataNetworkItemView") class]]) {
            dataNetWorkItemView = subView;
            break;
        }
    }

    NetWorkType networkType = NetWorkType_None;
    switch ([[dataNetWorkItemView valueForKey:@"dataNetworkType"] integerValue]) {
        case 0:
            NSLog(@"No wifi or cellular");
            networkType = NetWorkType_None;
            break;            
        case 1:
            NSLog(@"2G");
            networkType = NetWorkType_2G;
            break;           
        case 2:
            NSLog(@"3G");
            networkType = NetWorkType_3G;
            break;          
        default:           
            NSLog(@"Wifi");
            networkType = NetWorkType_WIFI;
            break;
    }

return networkType;

  

使用這種方法要確保導航欄沒有被隱藏,如果導航欄被隱藏則取不到值。另外,該方法存在Bug,通過Reachability類,在網絡類型發生改變時,再執行該代碼,獲取的網絡類型數據沒有更新。如果程序進入后台再轉到前台,重新執行該代碼時,便可以重新獲取最新的網絡類型數據。這樣用戶體驗不好,當用戶在移動中,網絡類型發生改變,無法獲取最新的網絡類型,則頁面數據無法更新。(PS:如果哪位大神知道,有什么方法可以刷新數據值,望不吝賜教,感謝!)

 

2、通過SCNetworkReachability類

代碼:

  struct sockaddr_in zeroAddress;
    bzero(&zeroAddress, sizeof(zeroAddress));
    zeroAddress.sin_len = sizeof(zeroAddress);
    zeroAddress.sin_family = AF_INET;
    SCNetworkReachabilityRef defaultRouteReachability = SCNetworkReachabilityCreateWithAddress(NULL, (struct sockaddr *)&zeroAddress); //創建測試連接的引用:
    SCNetworkReachabilityFlags flags;
    SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags);

  if ((flags & kSCNetworkReachabilityFlagsReachable) == 0)  
    {
        return NetWorkType_None;   
    }

    NetWorkType retVal = NetWorkType_None;

    if ((flags & kSCNetworkReachabilityFlagsConnectionRequired) == 0)
    {
        retVal = NetWorkType_WIFI;
    }

    if ((((flags & kSCNetworkReachabilityFlagsConnectionOnDemand ) != 0) ||    
         (flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) != 0))
    {
        if ((flags & kSCNetworkReachabilityFlagsInterventionRequired) == 0)  
        {
      retVal = NetWorkType_WIFI;    
        }
    }

    if ((flags & kSCNetworkReachabilityFlagsIsWWAN) == kSCNetworkReachabilityFlagsIsWWAN)
    {
        if((flags & kSCNetworkReachabilityFlagsReachable) == kSCNetworkReachabilityFlagsReachable) {
            if ((flags & kSCNetworkReachabilityFlagsTransientConnection) == kSCNetworkReachabilityFlagsTransientConnection) {
                retVal = NetWorkType_3G;
                if((flags & kSCNetworkReachabilityFlagsConnectionRequired) == kSCNetworkReachabilityFlagsConnectionRequired) {
                    retVal = NetWorkType_2G;
                }
            }
        }
    }

    return retVal;

這種方法跟Reachability的方法相同,也無法區分2G網和3g網,但是網上有人測試可以區分,如果有人知道原因,希望指正,謝謝!

 

3、使用SoftwareUpdateService.framework(私有API)

准備工作:

導出生成私有API的頭文件聲明
使用私有或未公開的API,首先需要導出其對應的頭文件,在頭文件里有相關函數的聲明。
工具:
class-dump
class-dump可以從編譯后的Objective-C的二進制文件中提取對應的數據結構及函數等聲明。
使用方法:
為了能在任意目錄下使用class-dump命令,首先建議把class-dump文件拷貝到/user/local/bin/目錄下,然后就可以在任意目錄下執行以下命令:
class-dump /Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator3.0.sdk/System/Library/Frameworks/SoftwareUpdateServices.framework/ >SUKit.h

但是bulidsetting 設置framework的search path 時要設置真實的私有庫路徑,因為我們要用它的可執行文件,只有頭文件是不行的。

代碼:

NSBundle *b =  [NSBundle bundleWithPath:@"/System/Library/PrivateFrameworks/SoftwareUpdateServices.framework"];

     if ([b load]) {

        // load Class from STRING

      SUNetworkMonitor *networkMonitor = [SUNetworkMonitor sharedInstance];
         int netType = [networkMonitor currentNetworkType];
         NetWorkType networkType = NetWorkType_None;
         switch ( netType ) {
             case 0:
                 NSLog(@"No wifi or cellular");
                 networkType = NetWorkType_None;
                 break;
             case 1:
                 NSLog(@"WIFI");
                 networkType = NetWorkType_WIFI;
                break;
             case 2:
                 NSLog(@"2G");
                 networkType = NetWorkType_2G;
                break;                
             case 3:
                 NSLog(@"3G");
                 networkType = NetWorkType_3G;
                 break;
             default:
                 break;
        }
return networkType; } return NetWorkType_None;

  

這種方法可以獲取網絡類型,並且在網絡類型改變時,獲取最新的網絡類型。目前還沒有發現Bug,只是准備階段的工作比較麻煩。

 

4、最后一種方法,就是利用IOS7系統自帶的API獲取。只是,IOS7以下的系統版本需要上述的方法獲取網絡類型。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM