您的位置:首页 > 移动开发 > IOS开发

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

2013-09-06 15:32 537 查看
由于设计的游戏需要有一些联网请求,但有时候在设备未连接网络的情况下,如果对网络情况不加以判断,则可能造成游戏为了等游戏超时,浪费不必要的时间。
所以在游戏启动时检测一下网络状况是很必要的,而且当玩家的设备连接上网络以后,有一个回调函数也是非常必要的一件事儿,这样可能更方便我们在后台下载数据库等信息。

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
plaincopy

#import <sys/socket.h>

#import <netinet/in.h>

#import <netinet6/in6.h>

#import <arpa/inet.h>

#import <ifaddrs.h>

#import <netdb.h>

#import <CoreFoundation/CoreFoundation.h>

#import "Reachability.h"

#define kShouldPrintReachabilityFlags 1

static void PrintReachabilityFlags(SCNetworkReachabilityFlags flags, const char* comment)

{

#if kShouldPrintReachabilityFlags

NSLog(@"Reachability Flag Status: %c%c %c%c%c%c%c%c%c %s\n",

(flags & kSCNetworkReachabilityFlagsIsWWAN) ? 'W' : '-',//当前网络为蜂窝网络,即3G或者GPRS

(flags & kSCNetworkReachabilityFlagsReachable) ? 'R' : '-',//网络请求地址可达

(flags & kSCNetworkReachabilityFlagsTransientConnection) ? 't' : '-',

(flags & kSCNetworkReachabilityFlagsConnectionRequired) ? 'c' : '-',

(flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) ? 'C' : '-',

(flags & kSCNetworkReachabilityFlagsInterventionRequired) ? 'i' : '-',

(flags & kSCNetworkReachabilityFlagsConnectionOnDemand) ? 'D' : '-',

(flags & kSCNetworkReachabilityFlagsIsLocalAddress) ? 'l' : '-',//该值为一个本地地址

(flags & kSCNetworkReachabilityFlagsIsDirect) ? 'd' : '-',

comment

);

#endif

}

@implementation Reachability

static void ReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void* info)

{

#pragma unused (target, flags)

NSCAssert(info != NULL, @"info was NULL in ReachabilityCallback");

NSCAssert([(NSObject*) info isKindOfClass: [Reachability class]], @"info was wrong class in ReachabilityCallback");

//We're on the main RunLoop, so an NSAutoreleasePool is not necessary, but is added defensively

// in case someon uses the Reachablity object in a different thread.

NSAutoreleasePool* myPool = [[NSAutoreleasePool alloc] init];

Reachability* noteObject = (Reachability*) info;

// Post a notification to notify the client that the network reachability changed.

[[NSNotificationCenter defaultCenter] postNotificationName: kReachabilityChangedNotification object: noteObject];

[myPool release];

}

//启动探测网络

- (BOOL) startNotifier

{

BOOL retVal = NO;

SCNetworkReachabilityContext context = {0, self, NULL, NULL, NULL};

//SCNetworkReachabilitySetCallback函数为指定一个target(此处为reachabilityRef,即www.apple.com,在reachabilityWithHostName里设置的)

//当设备对于这个target链接状态发生改变时(比如断开链接,或者重新连上),则回调reachabilityCallback函数,

if(SCNetworkReachabilitySetCallback(reachabilityRef, ReachabilityCallback, &context))

{

//指定一个runloop给指定的target

if(SCNetworkReachabilityScheduleWithRunLoop(reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode))

{

retVal = YES;

}

}

return retVal;

}

//停止网络探测

- (void) stopNotifier

{

if(reachabilityRef!= NULL)

{

SCNetworkReachabilityUnscheduleFromRunLoop(reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);

}

}

- (void) dealloc

{

[self stopNotifier];

if(reachabilityRef!= NULL)

{

CFRelease(reachabilityRef);

}

[super dealloc];

}

//通过域名设定一个目标地址比如www.apple.com

+ (Reachability*) reachabilityWithHostName: (NSString*) hostName;

{

Reachability* retVal = NULL;

SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithName(NULL, [hostName UTF8String]);

if(reachability!= NULL)

{

retVal= [[[self alloc] init] autorelease];

if(retVal!= NULL)

{

retVal->reachabilityRef = reachability;

retVal->localWiFiRef = NO;

}

}

return retVal;

}

//通过ip地址设定一个目标的地址,可以加端口号,貌似我实验的不太成功

+ (Reachability*) reachabilityWithAddress: (const struct sockaddr_in*) hostAddress;

{

SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (const struct sockaddr*)hostAddress);

Reachability* retVal = NULL;

if(reachability!= NULL)

{

retVal= [[[self alloc] init] autorelease];

if(retVal!= NULL)

{

retVal->reachabilityRef = reachability;

retVal->localWiFiRef = NO;

}

}

return retVal;

}

//检测当前网络能否连上internet

+ (Reachability*) reachabilityForInternetConnection;

{

struct sockaddr_in zeroAddress;

bzero(&zeroAddress, sizeof(zeroAddress));

zeroAddress.sin_len = sizeof(zeroAddress);

zeroAddress.sin_family = AF_INET;

return [self reachabilityWithAddress: &zeroAddress];

}

//检测当前网络是否能够连上本地wifi

+ (Reachability*) reachabilityForLocalWiFi;

{

struct sockaddr_in localWifiAddress;

bzero(&localWifiAddress, sizeof(localWifiAddress));

localWifiAddress.sin_len = sizeof(localWifiAddress);

localWifiAddress.sin_family = AF_INET;

// IN_LINKLOCALNETNUM is defined in <netinet/in.h> as 169.254.0.0

localWifiAddress.sin_addr.s_addr = htonl(IN_LINKLOCALNETNUM);

Reachability* retVal = [self reachabilityWithAddress: &localWifiAddress];

if(retVal!= NULL)

{

retVal->localWiFiRef = YES;

}

return retVal;

}

#pragma mark Network Flag Handling

- (NetworkStatus) localWiFiStatusForFlags: (SCNetworkReachabilityFlags) flags

{

PrintReachabilityFlags(flags, "localWiFiStatusForFlags");

BOOL retVal = NotReachable;

if((flags & kSCNetworkReachabilityFlagsReachable) && (flags & kSCNetworkReachabilityFlagsIsDirect))

{

retVal = ReachableViaWiFi;

}

return retVal;

}

//通过flags返回当前网络状态

- (NetworkStatus) networkStatusForFlags: (SCNetworkReachabilityFlags) flags

{

PrintReachabilityFlags(flags, "networkStatusForFlags");

if ((flags & kSCNetworkReachabilityFlagsReachable) == 0)

{

// if target host is not reachable

return NotReachable;

}

BOOL retVal = NotReachable;

if ((flags & kSCNetworkReachabilityFlagsConnectionRequired) == 0)

{

// if target host is reachable and no connection is required

// then we'll assume (for now) that your on Wi-Fi

retVal = ReachableViaWiFi;

}

if ((((flags & kSCNetworkReachabilityFlagsConnectionOnDemand ) != 0) ||

(flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) != 0))

{

// ... and the connection is on-demand (or on-traffic) if the

// calling application is using the CFSocketStream or higher APIs

if ((flags & kSCNetworkReachabilityFlagsInterventionRequired) == 0)

{

// ... and no [user] intervention is needed

retVal = ReachableViaWiFi;

}

}

if ((flags & kSCNetworkReachabilityFlagsIsWWAN) == kSCNetworkReachabilityFlagsIsWWAN)

{

// ... but WWAN connections are OK if the calling application

// is using the CFNetwork (CFSocketStream?) APIs.

retVal = ReachableViaWWAN;

}

return retVal;

}

- (BOOL) connectionRequired;

{

NSAssert(reachabilityRef != NULL, @"connectionRequired called with NULL reachabilityRef");

SCNetworkReachabilityFlags flags;

if (SCNetworkReachabilityGetFlags(reachabilityRef, &flags))

{

return (flags & kSCNetworkReachabilityFlagsConnectionRequired);

}

return NO;

}

//获得当前网络状态

- (NetworkStatus) currentReachabilityStatus

{

NSAssert(reachabilityRef != NULL, @"currentNetworkStatus called with NULL reachabilityRef");

NetworkStatus retVal = NotReachable;

SCNetworkReachabilityFlags flags;

if (SCNetworkReachabilityGetFlags(reachabilityRef, &flags))

{

if(localWiFiRef)

{

retVal = [self localWiFiStatusForFlags: flags];

}

else

{

retVal = [self networkStatusForFlags: flags];

}

}

return retVal;

}

@end

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

[cpp] view
plaincopy

- (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(无法连接)

转载:http://blog.csdn.net/devfun/article/details/7365774
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: