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

来源:互联网 发布:淘宝刷好的评价 英文 编辑:程序博客网 时间:2024/05/18 20:52

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

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

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


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

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



原创粉丝点击