获取网络连接状态目前有多种方法,其他的都比较好理解,不过都有些局限性,利用statusBar的subViews的信息来获取网络状态是比较简明的,但是在隐藏状态栏的情况下失效,还有使用私有API的方法,这里我们谈谈怎么用Reachability实现判断当前网络状态,包含无连接/2G/3G/4G/wifi。
首先了解下 网络连接标识 SCNetworkReachabilityFlags
typedef CF_OPTIONS(uint32_t, SCNetworkReachabilityFlags) {
kSCNetworkReachabilityFlagsTransientConnection = 1<<0, // 可以通过瞬时连接(例如PPP---点对点通讯协议) 链接到给定的节点名和地址
kSCNetworkReachabilityFlagsReachable = 1<<1, // 当前网络配置可以请求到给定的节点名和地址
kSCNetworkReachabilityFlagsConnectionRequired = 1<<2, // 当前网络配置可以请求到给定的节点名和地址,但必须先创建一个连接。如果创建这个标识,需要象征性地生成kSCNetworkReachabilityFlagsConnectionOnTraffic
, kSCNetworkReachabilityFlagsConnectionOnDemand
, 或者 kSCNetworkReachabilityFlagsIsWWAN 等标识来指明需要创建的连接类型。如果用户需要手动创建连接,kSCNetworkReachabilityFlagsInterventionRequired标识也将被生成
kSCNetworkReachabilityFlagsConnectionOnTraffic = 1<<3, //当前网络配置可以请求到给定的节点名和地址,但必须先创建一个连接。定向到指定节点或地址的通信将发起该连接,该标识原来名为kSCNetworkReachabilityFlagsConnectionAutomatic
kSCNetworkReachabilityFlagsInterventionRequired = 1<<4, //当前网络配置可以请求到给定的节点名和地址,但必须先创建一个连接。
用户需要通过某些方式的介入来创建该连接,比如提供密码、认证口令等。一般的,只有在一个拨号通信的配置中,在自动连接过程中发生某些错误(比如没有拨号音,没有回应,无效的密码等),这种情况下,PPP通信将会终止连接直到用户介入。
kSCNetworkReachabilityFlagsConnectionOnDemand = 1<<5, //当前网络配置可以请求到给定的节点名和地址,但必须先创建一个连接。该请求一经CFSocketStream程序接口请求就创建,其他的函数不会创建该连接
kSCNetworkReachabilityFlagsIsLocalAddress = 1<<16, // 所请求的节点或地址为连接到当前系统的网络节点
kSCNetworkReachabilityFlagsIsDirect = 1<<17, // 网络通信不会通过网关连接给定的节点名和地址,而是直接路由到系统中的一个接口上。
#if TARGET_OS_IPHONE
kSCNetworkReachabilityFlagsIsWWAN = 1<<18, // 可通过蜂窝数据网络访问给定的节点或地址
#endif // TARGET_OS_IPHONE
kSCNetworkReachabilityFlagsConnectionAutomatic = kSCNetworkReachabilityFlagsConnectionOnTraffic
};
然后就是通过这些标识来判断当前网络类型了。
那么第一步就是获取这些标识
SCNetworkReachabilityFlags flags;
if (SCNetworkReachabilityGetFlags(_reachabilityRef, &flags))
{
// 此处获得的flags即能指示当前网络环境的标识
}
再对flags进行分析判断,了解网络类型
if ((flags & kSCNetworkReachabilityFlagsReachable) == 0)
{
// 无法连接网络
}
if ((flags & kSCNetworkReachabilityFlagsConnectionRequired) == 0)
{
// 给定的节点或地址是可达的,并且不需要先请求一个多余的连接,那么我们可以判断是通过Wi-Fi连接的(不需要密码)
}
if ((((flags & kSCNetworkReachabilityFlagsConnectionOnDemand ) != 0) ||
(flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) != 0))
{
// 通过CFSocketStream或者更高级的APIs发起on-demand (或者 on-traffic)请求
if ((flags & kSCNetworkReachabilityFlagsInterventionRequired) == 0)
{
// 不需要用户介入的情况下,我们判断为Wi-Fi
}
}
if ((flags & kSCNetworkReachabilityFlagsIsWWAN) == kSCNetworkReachabilityFlagsIsWWAN)
{
/*
通过CFNetwork APIs发起蜂窝数据网络请求
*/
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0)
{
/*
蜂窝数据网络分2/3/4G,此处使用CTTelephonyNetworkInfo来判断,只适用于iOS 7及以上
*/
CTTelephonyNetworkInfo * info = [[CTTelephonyNetworkInfo alloc] init];
NSString *currentRadioAccessTechnology = info.currentRadioAccessTechnology;
if (currentRadioAccessTechnology)
{
if ([currentRadioAccessTechnology isEqualToString:CTRadioAccessTechnologyLTE])
{
// 4G
}
else if ([currentRadioAccessTechnology isEqualToString:CTRadioAccessTechnologyEdge] || [currentRadioAccessTechnology isEqualToString:CTRadioAccessTechnologyGPRS] || [currentRadioAccessTechnology isEqualToString:CTRadioAccessTechnologyCDMA1x])
{
// 2G
}
else
{
// 3G
}
}
}
if ((flags & kSCNetworkReachabilityFlagsTransientConnection) == kSCNetworkReachabilityFlagsTransientConnection)
{
if((flags & kSCNetworkReachabilityFlagsConnectionRequired) == kSCNetworkReachabilityFlagsConnectionRequired)
{
// 2G
}
// 3G
}
// 由于flags标识中不能提供4G的具体标识,故走到这一步即可认为当前为4G网络环境
// 4G
}