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

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

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

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

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

  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里面调用的部分

- (void) applicationDidFinishLaunching: (UIApplication* )application 

{

    #pragma unused(application)

    contentView.backgroundColor = [UIColor groupTableViewBackgroundColor];

    

    summaryLabel.hidden = YES;        

    

 

    //这句是设定一个回调函数reachability,当网络条件发生变化时则去调用reachabilityChanged

    [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(reachabilityChanged:) name: kReachabilityChangedNotification object: nil];

 

    //Change the host name here to change the server your monitoring

    remoteHostLabel.text = [NSString stringWithFormat: @"Remote Host: %@", @"www.apple.com"];

    //设定target地址,这里是www.apple.com

    hostReach = [[Reachability reachabilityWithHostName: @"www.apple.com"] retain];

    //启动网络条件检测

    [hostReach startNotifier];

    //更新UI的网络状态显示

    [self updateInterfaceWithReachability: hostReach];

    

    //探测是否能连上internet网

    internetReach = [[Reachability reachabilityForInternetConnection] retain];

    [internetReach startNotifier];

    [self updateInterfaceWithReachability: internetReach];

 

    //探测wifi是否开启

    wifiReach = [[Reachability reachabilityForLocalWiFi] retain];

    [wifiReach startNotifier];

    [self updateInterfaceWithReachability: wifiReach];

 

    [window makeKeyAndVisible];

    

}









//如需要查看网络状态,如下调用即可

NetworkStatus netStatus = [curReach currentReachabilityStatus];

netStatus有ReachableViaWWAN(蜂窝网络3G之类的),ReachableViaWiFi(wifi连接),NotReachable(无法连接)

 

 

你可能感兴趣的:(wifi)