关于在iOS设备上探测WIFI,3G,GPRS使用情况的细节

由于设计的游戏需要有一些联网请求,但有时候在设备未连接网络的情况下,如果对网络情况不加以判断,则可能造成游戏为了等游戏超时,浪费不必要的时间。

所以在游戏启动时检测一下网络状况是很必要的,而且当玩家的设备连接上网络以后,有一个回调函数也是非常必要的一件事儿,这样可能更方便我们在后台下载数据库等信息。

apple为我们提供了一套范例代码,下面我就来分析一下这段代码。
范例代码地址在:https://developer.apple.com/library/ios/#samplecode/Reachability/Listings/Classes_ReachabilityAppDelegate_m.html#//apple_ref/doc/uid/DTS40007324-Classes_ReachabilityAppDelegate_m-DontLinkElementID_4


范例中包含两部分,一部分是appdelegate,一部分是reachability


[cpp]  view plain copy
  1. #import <sys/socket.h>  
  2. #import <netinet/in.h>  
  3. #import <netinet6/in6.h>  
  4. #import <arpa/inet.h>  
  5. #import <ifaddrs.h>  
  6. #import <netdb.h>  
  7.    
  8. #import <CoreFoundation/CoreFoundation.h>  
  9.    
  10. #import "Reachability.h"  
  11.    
  12. #define kShouldPrintReachabilityFlags 1  
  13.    
  14. static void PrintReachabilityFlags(SCNetworkReachabilityFlags    flags, const char* comment)  
  15. {  
  16. #if kShouldPrintReachabilityFlags  
  17.       
  18.     NSLog(@"Reachability Flag Status: %c%c %c%c%c%c%c%c%c %s\n",  
  19.             (flags & kSCNetworkReachabilityFlagsIsWWAN)               ? 'W' : '-',//当前网络为蜂窝网络,即3G或者GPRS  
  20.             (flags & kSCNetworkReachabilityFlagsReachable)            ? 'R' : '-',//网络请求地址可达  
  21.               
  22.             (flags & kSCNetworkReachabilityFlagsTransientConnection)  ? 't' : '-',  
  23.             (flags & kSCNetworkReachabilityFlagsConnectionRequired)   ? 'c' : '-',  
  24.             (flags & kSCNetworkReachabilityFlagsConnectionOnTraffic)  ? 'C' : '-',  
  25.             (flags & kSCNetworkReachabilityFlagsInterventionRequired) ? 'i' : '-',  
  26.             (flags & kSCNetworkReachabilityFlagsConnectionOnDemand)   ? 'D' : '-',  
  27.             (flags & kSCNetworkReachabilityFlagsIsLocalAddress)       ? 'l' : '-',//该值为一个本地地址  
  28.             (flags & kSCNetworkReachabilityFlagsIsDirect)             ? 'd' : '-',  
  29.             comment  
  30.             );  
  31. #endif  
  32. }  
  33.    
  34.    
  35. @implementation Reachability  
  36. static void ReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void* info)  
  37. {  
  38.     #pragma unused (target, flags)  
  39.     NSCAssert(info != NULL, @"info was NULL in ReachabilityCallback");  
  40.     NSCAssert([(NSObject*) info isKindOfClass: [Reachability class]], @"info was wrong class in ReachabilityCallback");  
  41.    
  42.     //We're on the main RunLoop, so an NSAutoreleasePool is not necessary, but is added defensively  
  43.     // in case someon uses the Reachablity object in a different thread.  
  44.     NSAutoreleasePool* myPool = [[NSAutoreleasePool alloc] init];  
  45.       
  46.     Reachability* noteObject = (Reachability*) info;  
  47.     // Post a notification to notify the client that the network reachability changed.  
  48.     [[NSNotificationCenter defaultCenter] postNotificationName: kReachabilityChangedNotification object: noteObject];  
  49.       
  50.     [myPool release];  
  51. }  
  52.   
  53.   
  54.   
  55. //启动探测网络   
  56. - (BOOL) startNotifier  
  57. {  
  58.     BOOL retVal = NO;  
  59.     SCNetworkReachabilityContext    context = {0, self, NULL, NULL, NULL};  
  60.     //SCNetworkReachabilitySetCallback函数为指定一个target(此处为reachabilityRef,即www.apple.com,在reachabilityWithHostName里设置的)  
  61.     //当设备对于这个target链接状态发生改变时(比如断开链接,或者重新连上),则回调reachabilityCallback函数,  
  62.     if(SCNetworkReachabilitySetCallback(reachabilityRef, ReachabilityCallback, &context))  
  63.     {  
  64.         //指定一个runloop给指定的target  
  65.         if(SCNetworkReachabilityScheduleWithRunLoop(reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode))  
  66.         {  
  67.             retVal = YES;  
  68.         }  
  69.     }  
  70.     return retVal;  
  71. }  
  72.  //停止网络探测  
  73. - (void) stopNotifier  
  74. {  
  75.     if(reachabilityRef!= NULL)  
  76.     {  
  77.         SCNetworkReachabilityUnscheduleFromRunLoop(reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);  
  78.     }  
  79. }  
  80.    
  81. - (void) dealloc  
  82. {  
  83.     [self stopNotifier];  
  84.     if(reachabilityRef!= NULL)  
  85.     {  
  86.         CFRelease(reachabilityRef);  
  87.     }  
  88.     [super dealloc];  
  89. }  
  90.  //通过域名设定一个目标地址比如www.apple.com  
  91. + (Reachability*) reachabilityWithHostName: (NSString*) hostName;  
  92. {  
  93.     Reachability* retVal = NULL;  
  94.     SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithName(NULL, [hostName UTF8String]);  
  95.     if(reachability!= NULL)  
  96.     {  
  97.         retVal= [[[self alloc] init] autorelease];  
  98.         if(retVal!= NULL)  
  99.         {  
  100.             retVal->reachabilityRef = reachability;  
  101.             retVal->localWiFiRef = NO;  
  102.         }  
  103.     }  
  104.     return retVal;  
  105. }  
  106.   //通过ip地址设定一个目标的地址,可以加端口号,貌似我实验的不太成功  
  107. + (Reachability*) reachabilityWithAddress: (const struct sockaddr_in*) hostAddress;  
  108. {  
  109.     SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (const struct sockaddr*)hostAddress);  
  110.     Reachability* retVal = NULL;  
  111.     if(reachability!= NULL)  
  112.     {  
  113.         retVal= [[[self alloc] init] autorelease];  
  114.         if(retVal!= NULL)  
  115.         {  
  116.             retVal->reachabilityRef = reachability;  
  117.             retVal->localWiFiRef = NO;  
  118.         }  
  119.     }  
  120.     return retVal;  
  121. }  
  122.  //检测当前网络能否连上internet  
  123. + (Reachability*) reachabilityForInternetConnection;  
  124. {  
  125.     struct sockaddr_in zeroAddress;  
  126.     bzero(&zeroAddress, sizeof(zeroAddress));  
  127.     zeroAddress.sin_len = sizeof(zeroAddress);  
  128.     zeroAddress.sin_family = AF_INET;  
  129.     return [self reachabilityWithAddress: &zeroAddress];  
  130. }  
  131.  //检测当前网络是否能够连上本地wifi  
  132. + (Reachability*) reachabilityForLocalWiFi;  
  133. {  
  134.     struct sockaddr_in localWifiAddress;  
  135.     bzero(&localWifiAddress, sizeof(localWifiAddress));  
  136.     localWifiAddress.sin_len = sizeof(localWifiAddress);  
  137.     localWifiAddress.sin_family = AF_INET;  
  138.     // IN_LINKLOCALNETNUM is defined in <netinet/in.h> as 169.254.0.0  
  139.     localWifiAddress.sin_addr.s_addr = htonl(IN_LINKLOCALNETNUM);  
  140.     Reachability* retVal = [self reachabilityWithAddress: &localWifiAddress];  
  141.     if(retVal!= NULL)  
  142.     {  
  143.         retVal->localWiFiRef = YES;  
  144.     }  
  145.     return retVal;  
  146. }  
  147.    
  148. #pragma mark Network Flag Handling  
  149.    
  150. - (NetworkStatus) localWiFiStatusForFlags: (SCNetworkReachabilityFlags) flags  
  151. {  
  152.     PrintReachabilityFlags(flags, "localWiFiStatusForFlags");  
  153.    
  154.     BOOL retVal = NotReachable;  
  155.     if((flags & kSCNetworkReachabilityFlagsReachable) && (flags & kSCNetworkReachabilityFlagsIsDirect))  
  156.     {  
  157.         retVal = ReachableViaWiFi;    
  158.     }  
  159.     return retVal;  
  160. }  
  161.  //通过flags返回当前网络状态  
  162. - (NetworkStatus) networkStatusForFlags: (SCNetworkReachabilityFlags) flags  
  163. {  
  164.     PrintReachabilityFlags(flags, "networkStatusForFlags");  
  165.     if ((flags & kSCNetworkReachabilityFlagsReachable) == 0)  
  166.     {  
  167.         // if target host is not reachable  
  168.         return NotReachable;  
  169.     }  
  170.    
  171.     BOOL retVal = NotReachable;  
  172.       
  173.     if ((flags & kSCNetworkReachabilityFlagsConnectionRequired) == 0)  
  174.     {  
  175.         // if target host is reachable and no connection is required  
  176.         //  then we'll assume (for now) that your on Wi-Fi  
  177.         retVal = ReachableViaWiFi;  
  178.     }  
  179.       
  180.       
  181.     if ((((flags & kSCNetworkReachabilityFlagsConnectionOnDemand ) != 0) ||  
  182.         (flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) != 0))  
  183.     {  
  184.             // ... and the connection is on-demand (or on-traffic) if the  
  185.             //     calling application is using the CFSocketStream or higher APIs  
  186.    
  187.             if ((flags & kSCNetworkReachabilityFlagsInterventionRequired) == 0)  
  188.             {  
  189.                 // ... and no [user] intervention is needed  
  190.                 retVal = ReachableViaWiFi;  
  191.             }  
  192.         }  
  193.       
  194.     if ((flags & kSCNetworkReachabilityFlagsIsWWAN) == kSCNetworkReachabilityFlagsIsWWAN)  
  195.     {  
  196.         // ... but WWAN connections are OK if the calling application  
  197.         //     is using the CFNetwork (CFSocketStream?) APIs.  
  198.         retVal = ReachableViaWWAN;  
  199.     }  
  200.     return retVal;  
  201. }  
  202.    
  203. - (BOOL) connectionRequired;  
  204. {  
  205.     NSAssert(reachabilityRef != NULL, @"connectionRequired called with NULL reachabilityRef");  
  206.     SCNetworkReachabilityFlags flags;  
  207.     if (SCNetworkReachabilityGetFlags(reachabilityRef, &flags))  
  208.     {  
  209.         return (flags & kSCNetworkReachabilityFlagsConnectionRequired);  
  210.     }  
  211.     return NO;  
  212. }  
  213.  //获得当前网络状态  
  214. - (NetworkStatus) currentReachabilityStatus  
  215. {  
  216.     NSAssert(reachabilityRef != NULL, @"currentNetworkStatus called with NULL reachabilityRef");  
  217.     NetworkStatus retVal = NotReachable;  
  218.     SCNetworkReachabilityFlags flags;  
  219.     if (SCNetworkReachabilityGetFlags(reachabilityRef, &flags))  
  220.     {  
  221.         if(localWiFiRef)  
  222.         {  
  223.             retVal = [self localWiFiStatusForFlags: flags];  
  224.         }  
  225.         else  
  226.         {  
  227.             retVal = [self networkStatusForFlags: flags];  
  228.         }  
  229.     }  
  230.     return retVal;  
  231. }  
  232. @end  

以上的部分为具体实现的部分,下面我们再来看在appdelegate里面调用的部分

[cpp]  view plain copy
  1. - (void) applicationDidFinishLaunching: (UIApplication* )application   
  2. {  
  3.     #pragma unused(application)  
  4.     contentView.backgroundColor = [UIColor groupTableViewBackgroundColor];  
  5.       
  6.     summaryLabel.hidden = YES;          
  7.       
  8.    
  9.     //这句是设定一个回调函数reachability,当网络条件发生变化时则去调用reachabilityChanged  
  10.     [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(reachabilityChanged:) name: kReachabilityChangedNotification object: nil];  
  11.    
  12.     //Change the host name here to change the server your monitoring  
  13.     remoteHostLabel.text = [NSString stringWithFormat: @"Remote Host: %@", @"www.apple.com"];  
  14.     //设定target地址,这里是www.apple.com  
  15.     hostReach = [[Reachability reachabilityWithHostName: @"www.apple.com"] retain];  
  16.     //启动网络条件检测  
  17.     [hostReach startNotifier];  
  18.     //更新UI的网络状态显示  
  19.     [self updateInterfaceWithReachability: hostReach];  
  20.       
  21.     //探测是否能连上internet网  
  22.     internetReach = [[Reachability reachabilityForInternetConnection] retain];  
  23.     [internetReach startNotifier];  
  24.     [self updateInterfaceWithReachability: internetReach];  
  25.    
  26.     //探测wifi是否开启  
  27.     wifiReach = [[Reachability reachabilityForLocalWiFi] retain];  
  28.     [wifiReach startNotifier];  
  29.     [self updateInterfaceWithReachability: wifiReach];  
  30.    
  31.     [window makeKeyAndVisible];  
  32.       
  33. }  
  34.   
  35.   
  36.   
  37.   
  38. //如需要查看网络状态,如下调用即可  
  39. NetworkStatus netStatus = [curReach currentReachabilityStatus];  
  40. netStatus有ReachableViaWWAN(蜂窝网络3G之类的),ReachableViaWiFi(wifi连接),NotReachable(无法连接)  

转载:http://blog.csdn.net/devfun/article/details/7365774

你可能感兴趣的:(关于在iOS设备上探测WIFI,3G,GPRS使用情况的细节)