iOSがネットワークタイプを取得する4つの方法

6203 ワード

ReachabilityクラスはWIFIとWWANタイプしか区別できませんが、2 Gネットワークと3 Gネットワークは区別できません.
ネット上にもいくつかの方法がありますが、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の方法と同じで、2 Gネットと3 gネットを区別することもできませんが、ネット上で誰かがテストして区別することができます.もし誰かが原因を知っていたら、指摘してほしいです.ありがとうございます.
 
3、SoftwareUpdateServicesを使用する.framework(プライベートAPI)
準備:
プライベートAPIを生成するヘッダファイル宣言をエクスポートプライベートまたは非公開のAPIを使用するには、まず、対応するヘッダファイルをエクスポートする必要があります.ヘッダファイルには関連関数の宣言があります.ツール:class-dumpclass-dumpコンパイルされたObjective-Cのバイナリファイルから対応するデータ構造や関数などの宣言を抽出できます.使用方法:任意のディレクトリでclass-dumpコマンドを使用できるようにするには、まずclass-dumpファイルを/user/local/bin/ディレクトリにコピーすることを提案し、その後、任意のディレクトリで以下のコマンドを実行することができる:class-dump/developer/Platforms/iPhone Simulator.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;

  
この方法は、ネットワークタイプを取得し、ネットワークタイプが変更されたときに最新のネットワークタイプを取得することができる.まだバグは発見されていませんが、準備段階の作業が面倒です.
 
4、最後の方法は、IOS 7システムが持参したAPIを利用して取得することである.ただし、IOS 7以下のシステムバージョンでは、上記の方法でネットワークタイプを取得する必要がある.