iOS 實時檢測網絡狀態

        最近遇到一個功能就是根據用戶當前的網絡狀,用戶未聯網需要提示一下,如果是Wifi可以推薦一些圖片新聞,如果是3G模式設置爲無圖的模式,獲取網絡狀態比較簡單,畢竟中國現在的流量還是一個比較貴的狀態,哪天用戶發現App消耗流量過多說不定就幹掉了App 不過蘋果的 Reachability 都解決了以上問題,使用起來也比較方便,具體的稍微簡單分析一下。


Reachability.h頭文件代碼:

<span style="font-size:18px;">#import <Foundation/Foundation.h>
#import <SystemConfiguration/SystemConfiguration.h>
#import <netinet/in.h>

//http://www.cnblogs.com/xiaofeixiang
typedef 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</span>

Reachability.m文件:

<span style="font-size:18px;">#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 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",
      //當前網絡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 NO
  SCNetworkReachabilityRef _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</span>

AppDelegate中的實現:
<span style="font-size:18px;">- (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;
}

</span>

回調函數:

<span style="font-size:18px;">- (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;
  }
}</span>


發佈了46 篇原創文章 · 獲贊 5 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章