標籤:
最近遇到一個功能就是根據使用者當前的網路狀,使用者未連網需要提示一下,如果是Wifi可以推薦一些圖片新聞,如果是3G模式設定為無圖的模式,擷取網路狀態比較簡單,畢竟中國現在的流量還是一個比較貴的狀態,哪天使用者發現App消耗流量過多說不定就幹掉了App。不過蘋果的Reachability都解決了以上問題,使用起來也比較方便,具體的稍微簡單分析一下。
Reachability.h標頭檔代碼:
#import <Foundation/Foundation.h>#import <SystemConfiguration/SystemConfiguration.h>#import <netinet/in.h>//http://www.cnblogs.com/xiaofeixiangtypedef enum : NSInteger {NotReachable = 0,ReachableViaWiFi,ReachableViaWWAN} NetworkStatus;extern NSString *kReachabilityChangedNotification;@interface Reachability : NSObject/*! * Use to check the reachability of a given host name. */+ (instancetype)reachabilityWithHostName:(NSString *)hostName;/*! * Use to check the reachability of a given IP address. */+ (instancetype)reachabilityWithAddress:(const struct sockaddr_in *)hostAddress;/*! * Checks whether the default route is available. Should be used by applications that do not connect to a particular host. */+ (instancetype)reachabilityForInternetConnection;/*! * Checks whether a local WiFi connection is available. */+ (instancetype)reachabilityForLocalWiFi;/*! * Start listening for reachability notifications on the current run loop. */- (BOOL)startNotifier;- (void)stopNotifier;- (NetworkStatus)currentReachabilityStatus;/*! * WWAN may be available, but not active until a connection has been established. WiFi may require a connection for VPN on Demand. */- (BOOL)connectionRequired;@end
Reachability.m檔案:
#import <arpa/inet.h>#import <ifaddrs.h>#import <netdb.h>#import <sys/socket.h>#import <CoreFoundation/CoreFoundation.h>#import "Reachability.h"NSString *kReachabilityChangedNotification = @"kNetworkReachabilityChangedNotification";#pragma mark - Supporting functions#define kShouldPrintReachabilityFlags 1static void PrintReachabilityFlags(SCNetworkReachabilityFlags flags, const char* comment){#if kShouldPrintReachabilityFlags NSLog(@"Reachability Flag Status: %c%c %c%c%c%c%c%c%c %s\n", //當前網路2G/3G/4G蜂窩網路 (flags & kSCNetworkReachabilityFlagsIsWWAN)? ‘W‘ : ‘-‘, //網路是否可達 (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}static void ReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void* info){#pragma unused (target, flags)NSCAssert(info != NULL, @"info was NULL in ReachabilityCallback");NSCAssert([(__bridge NSObject*) info isKindOfClass: [Reachability class]], @"info was wrong class in ReachabilityCallback"); //http://www.cnblogs.com/xiaofeixiang Reachability* noteObject = (__bridge Reachability *)info; // Post a notification to notify the client that the network reachability changed. [[NSNotificationCenter defaultCenter] postNotificationName: kReachabilityChangedNotification object: noteObject];}#pragma mark - Reachability implementation@implementation Reachability{BOOL _alwaysReturnLocalWiFiStatus; //default is NOSCNetworkReachabilityRef _reachabilityRef;}//通過網域名稱進行執行個體化 部落格園-Fly_Elephant+ (instancetype)reachabilityWithHostName:(NSString *)hostName{Reachability* returnValue = NULL;SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithName(NULL, [hostName UTF8String]);if (reachability != NULL){returnValue= [[self alloc] init];if (returnValue != NULL){returnValue->_reachabilityRef = reachability;returnValue->_alwaysReturnLocalWiFiStatus = NO;}}return returnValue;}//通過ip地址執行個體化Reachability+ (instancetype)reachabilityWithAddress:(const struct sockaddr_in *)hostAddress{SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (const struct sockaddr *)hostAddress);Reachability* returnValue = NULL;if (reachability != NULL){returnValue = [[self alloc] init];if (returnValue != NULL){returnValue->_reachabilityRef = reachability;returnValue->_alwaysReturnLocalWiFiStatus = NO;}}return returnValue;}//檢測是否能夠直接連上互連網+ (instancetype)reachabilityForInternetConnection{struct sockaddr_in zeroAddress;bzero(&zeroAddress, sizeof(zeroAddress));zeroAddress.sin_len = sizeof(zeroAddress);zeroAddress.sin_family = AF_INET; return [self reachabilityWithAddress:&zeroAddress];}//檢測當前網路是否能夠聯上wifi+ (instancetype)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* returnValue = [self reachabilityWithAddress: &localWifiAddress];if (returnValue != NULL){returnValue->_alwaysReturnLocalWiFiStatus = YES;} return returnValue;}#pragma mark - Start and stop notifier- (BOOL)startNotifier{BOOL returnValue = NO;SCNetworkReachabilityContext context = {0, (__bridge void *)(self), NULL, NULL, NULL}; //SCNetworkReachabilitySetCallback函數為指定一個target //當裝置對於這個target連結狀態發生改變時(比如取消連結,或者重新連上),則回調reachabilityCallback函數,if (SCNetworkReachabilitySetCallback(_reachabilityRef, ReachabilityCallback, &context)){if (SCNetworkReachabilityScheduleWithRunLoop(_reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode)){returnValue = YES;}} return returnValue;}- (void)stopNotifier{if (_reachabilityRef != NULL){SCNetworkReachabilityUnscheduleFromRunLoop(_reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);}}- (void)dealloc{[self stopNotifier];if (_reachabilityRef != NULL){CFRelease(_reachabilityRef);}}#pragma mark - Network Flag Handling- (NetworkStatus)localWiFiStatusForFlags:(SCNetworkReachabilityFlags)flags{PrintReachabilityFlags(flags, "localWiFiStatusForFlags");NetworkStatus returnValue = NotReachable;if ((flags & kSCNetworkReachabilityFlagsReachable) && (flags & kSCNetworkReachabilityFlagsIsDirect)){returnValue = ReachableViaWiFi;} return returnValue;}- (NetworkStatus)networkStatusForFlags:(SCNetworkReachabilityFlags)flags{PrintReachabilityFlags(flags, "networkStatusForFlags");if ((flags & kSCNetworkReachabilityFlagsReachable) == 0){// The target host is not reachable.return NotReachable;} NetworkStatus returnValue = NotReachable;if ((flags & kSCNetworkReachabilityFlagsConnectionRequired) == 0){/* If the target host is reachable and no connection is required then we‘ll assume (for now) that you‘re on Wi-Fi... */returnValue = 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... */ returnValue = ReachableViaWiFi; } }if ((flags & kSCNetworkReachabilityFlagsIsWWAN) == kSCNetworkReachabilityFlagsIsWWAN){/* ... but WWAN connections are OK if the calling application is using the CFNetwork APIs. */returnValue = ReachableViaWWAN;} return returnValue;}- (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 SCNetworkReachabilityRef");NetworkStatus returnValue = NotReachable;SCNetworkReachabilityFlags flags; if (SCNetworkReachabilityGetFlags(_reachabilityRef, &flags)){if (_alwaysReturnLocalWiFiStatus){returnValue = [self localWiFiStatusForFlags:flags];}else{returnValue = [self networkStatusForFlags:flags];}} return returnValue;}@end
AppDelegate中的實現:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { //添加一個系統通知 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(reachabilityChanged:) name:kReachabilityChangedNotification object:nil]; //初始化 self.internetReachability=[Reachability reachabilityForInternetConnection]; //通知添加到Run Loop [self.internetReachability startNotifier]; [self updateInterfaceWithReachability:_internetReachability]; return YES;}
回呼函數:
- (void) reachabilityChanged:(NSNotification *)note{ Reachability* curReach = [note object]; NSParameterAssert([curReach isKindOfClass:[Reachability class]]); [self updateInterfaceWithReachability:curReach];}- (void)updateInterfaceWithReachability:(Reachability *)reachability{ NetworkStatus netStatus = [reachability currentReachabilityStatus]; switch (netStatus) { case NotReachable: NSLog(@"====當前網路狀態不可達=======http://www.cnblogs.com/xiaofeixiang"); break; case ReachableViaWiFi: NSLog(@"====當前網路狀態為Wifi=======部落格園-Fly_Elephant"); break; case ReachableViaWWAN: NSLog(@"====當前網路狀態為3G=======keso"); break; }}
模式測試 Wifi模式-wuWifi-串連Wifi,顯示結果如下:
如果直接通過host執行個體化也可以:
NSString *remoteHostName = @"www.cnblogs.com/xiaofeixiang"; self.hostReachability = [Reachability reachabilityWithHostName:remoteHostName];
iOS開發-Reachability即時檢測Wifi,2G/3G/4G/網路狀態