iOS开发-Reachability实时检测Wifi,2G/3G/4G/网络状态

最近遇到一个功能就是根据用户当前的网络状,用户未联网需要提示一下,如果是Wifi可以推荐一些图片新闻,如果是3G模式设置为无图的模式,获取网络状态比较简单,毕竟中国现在的流量还是一个比较贵的状态,哪天用户发现App消耗流量过多说不定就干掉了App。不过苹果的Reachability都解决了以上问题,使用起来也比较方便,具体的稍微简单分析一下。

Reachability.h头文件代码:

#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

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 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

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];  
时间: 2024-11-03 14:02:55

iOS开发-Reachability实时检测Wifi,2G/3G/4G/网络状态的相关文章

iOS使用Reachability实时检测网络连接状况

//在程序的启动处,开启通知 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { //..... //开启网络状况的监听 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(reachabilityChanged:) name: kR

Android 统计Wifi/2G/3G/4G流量

需求: 统计Wifi/2G/3G/4G流量各多少 Issue: 一. 怎么判断2G/3G/4G 系统源码TelephonyManager类里提供了方法,只是隐藏了,所以可以参源码 二.怎么统计 Android 2.2后提供TrafficStats类,用来进行流量统计,具体使用参考手册 这里我用到了 static long  getTotalRxBytes()  //获取总的接受字节数,包含Mobile和WiFi等 static long  getTotalTxBytes()  //总的发送字节数

Android 判断用户2G/3G/4G移动数据网络

在做 Android App 的时候,为了给用户省流量,为了不激起用户的愤怒,为了更好的用户体验,是需要根据用户当前网络情况来做一些调整的,也可以在 App 的设置模块里,让用户自己选择,在 2G / 3G / 4G 网络条件下,是否允许请求一些流量比较大的数据. 通过 Android 提供的 TelephonyManager 和 ConnectivityManager 都可以获取到 NetworksInfo 对象,可以通过 getType() 获取类型,判断是 wifi 还是 mobile ,

转:Android 判断用户2G/3G/4G移动数据网络

Android 判断用户2G/3G/4G移动数据网络 在做 Android App 的时候,为了给用户省流量,为了不激起用户的愤怒,为了更好的用户体验,是需要根据用户当前网络情况来做一些调整的,也可以在 App 的设置模块里,让用户自己选择,在 2G / 3G / 4G 网络条件下,是否允许请求一些流量比较大的数据. 通过 Android 提供的 TelephonyManager 和 ConnectivityManager 都可以获取到 NetworksInfo 对象,可以通过 getType(

(转)Android 判断用户2G/3G/4G移动数据网络

在做 Android App 的时候,为了给用户省流量,为了不激起用户的愤怒,为了更好的用户体验,是需(要根据用户当前网络情况来做一些调整的,也可以在 App 的设置模块里,让用户自己选择,在 2G / 3G / 4G 网络条件下,是否允许请求一些流量比较大的数据. 通过 Android 提供的 TelephonyManager 和 ConnectivityManager 都可以获取到 NetworksInfo 对象,可以通过 getType() 获取类型,判断是 wifi 还是 mobile

iOS开发 - 检测网络状态(WIFI、2G/3G/4G)

检测网络状态 在网络应用中,需要对用户设备的网络状态进行实时监控,目的是 让用户了解自己的网络状态,防止一些误会(比如怪应用无能) 根据用户的网络状态进行智能处理,节省用户流量,提高用户体验 WIFI\3G网络:自动下载高清图片 低速网络:只下载缩略图 没有网络:只显示离线的缓存数据 苹果官方提供了一个叫Reachability的示例程序,便于开发者检测网络状态 https://developer.apple.com/library/ios/samplecode/Reachability/Rea

IOS的网络提示(E\2G\3G\4G\WIFI\无网)

1.介绍 网络提示是App开发中不可缺少的模块.现在App需求智能化,要求根据网络的变化可以自动做出合理的处理(包括提示.下载...等).对于网络的处理也非常简单,实现也就几行代码(这是因为,苹果对网络变化进行了整理). 苹果官方提供一个监控网络变化的文件名字为 Reachability.对于Reachability也有其不足的地方,它不能更详细的判断用户是那种手机网络,只是提供给开发者一个统称的表示. 2.官方 Reachability 的介绍 Reachability(官方)的获取方法是打开

iOS中利用CoreTelephony获取用户当前网络状态(判断2G,3G,4G)

前言: 在项目开发当中,往往需要利用网络.而用户的网络环境也需要我们开发者去注意,根据不同的网络状态作相应的优化,以提升用户体验. 但通常我们只会判断用户是在WIFI还是移动数据,而实际上,移动数据也分为2G/3G/4G等不同制式.而不同的网络制式又对用户体验产生 较为明显的影响(对于依赖网络的项目而言).因此很有必要对不同的网络制式作相应的优化. 而在iOS当中,无论是苹果官方提供的Reachability类还是较为常用的第三方网络类AFNetworking,它们提供的网络环境判断也仅限 于W

利用CoreTelephony获取用户当前网络状态(判断2G,3G,4G)

前言: 在项目开发当中,往往需要利用网络.而用户的网络环境也需要我们开发者去注意,根据不同的网络状态作相应的优化,以提升用户体验. 但通常我们只会判断用户是在WIFI还是移动数据,而实际上,移动数据也分为2G/3G/4G等不同制式.而不同的网络制式又对用户体验产生 较为明显的影响(对于依赖网络的项目而言).因此很有必要对不同的网络制式作相应的优化. 而在iOS当中,无论是苹果官方提供的Reachability类还是较为常用的第三方网络类AFNetworking,它们提供的网络环境判断也仅限 于W