日常开发中,出现网络突然断开或异常,在等待网络恢复或连通后需要重新加载数据等情况,那么监听网络状态就是必不可少的。在这里涉及到获取网络状态、监听网络以及网络是否正常通讯。
【获取网络类型】引入以下库文件:
#import <CoreTelephony/CTCarrier.h>
#import <CoreTelephony/CTTelephonyNetworkInfo.h>
【获取网络状态、监听网络】引入以下库文件:
#import <arpa/inet.h>
#import <ifaddrs.h>
#import <netdb.h>
#import <sys/socket.h>
#import <netinet/in.h>
#import <SystemConfiguration/SystemConfiguration.h>
Reachability.h
#import <UIKit/UIKit.h>
typedef enum : NSInteger {
NotReachable = 0,
ReachableViaWiFi,
ReachableViaWWAN
} NetworkStatus;
extern NSString *kReachabilityChangedNotification;
@interface Reachability : NSObject
+ (instancetype)reachabilityWithHostName:(NSString *)hostName;
+ (instancetype)reachabilityWithAddress:(const struct sockaddr *)hostAddress;
+ (instancetype)reachabilityForInternetConnection;
- (BOOL)startNotifier;
- (void)stopNotifier;
- (NetworkStatus)currentReachabilityStatus;
- (BOOL)connectionRequired;
@end
Reachability.m
#import <Foundation/Foundation.h>
#import <arpa/inet.h>
#import <ifaddrs.h>
#import <netdb.h>
#import <sys/socket.h>
#import <netinet/in.h>
#import <SystemConfiguration/SystemConfiguration.h>
#import <CoreFoundation/CoreFoundation.h>
#import "Reachability.h"
NSString *kReachabilityChangedNotification = @"kNetworkReachabilityChangedNotification";
#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' : '-',
(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");
Reachability* noteObject = (__bridge Reachability *)info;
// Post a notification to notify the client that the network reachability changed.
[[NSNotificationCenter defaultCenter] postNotificationName: kReachabilityChangedNotification object: noteObject];
}
@implementation Reachability
{
SCNetworkReachabilityRef _reachabilityRef;
}
+ (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;
}
else {
CFRelease(reachability);
}
}
return returnValue;
}
+ (instancetype)reachabilityWithAddress:(const struct sockaddr *)hostAddress
{
SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, hostAddress);
Reachability* returnValue = NULL;
if (reachability != NULL)
{
returnValue = [[self alloc] init];
if (returnValue != NULL)
{
returnValue->_reachabilityRef = reachability;
}
else {
CFRelease(reachability);
}
}
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: (const struct sockaddr *) &zeroAddress];
}
- (BOOL)startNotifier
{
BOOL returnValue = NO;
SCNetworkReachabilityContext context = {0, (__bridge void *)(self), NULL, NULL, NULL};
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)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))
{
returnValue = [self networkStatusForFlags:flags];
}
return returnValue;
}
@end
NetUtil.h
#import <UIKit/UIKit.h>
#import "Reachability.h"
/**
* 网络工具类
**/
@interface NetUtil : NSObject
/**
* 获取当前网络状态
*/
+ (NSInteger)getCurrentNetWorkStatus;
/**
* 获取当前网络类型
*/
+ (NSString *)getNetworkType;
/**
* 注册监听网络状态
*/
+ (void)registerObserveNetWorkStatus;
/**
* 取消监听网络状态
*/
+ (void)unregisterObserveNetWorkStatus;
@end
NetUtil.m
#import <Foundation/Foundation.h>
#import "NetUtil.h"
#import <CoreTelephony/CTCarrier.h>
#import <CoreTelephony/CTTelephonyNetworkInfo.h>
@implementation NetUtil
static Reachability *reachability;
+ (NSInteger)getCurrentNetWorkStatus{
Reachability *reach = [Reachability reachabilityWithHostName:@"www.apple.com"];
return [reach currentReachabilityStatus];
}
+ (NSString *)getNetworkType{
NSString *networkType = @"unknown";
switch ([self getCurrentNetWorkStatus]) {
case NotReachable:// 没有网络
{
networkType = @"no network";
}
break;
case ReachableViaWiFi:// Wifi
{
networkType = @"Wifi";
}
break;
case ReachableViaWWAN:// 手机自带网络
{
// 获取手机网络类型
CTTelephonyNetworkInfo *info = [[CTTelephonyNetworkInfo alloc] init];
NSString *currentStatus = info.currentRadioAccessTechnology;
if ([currentStatus isEqualToString:@"CTRadioAccessTechnologyGPRS"]) {
networkType = @"GPRS";
}else if ([currentStatus isEqualToString:@"CTRadioAccessTechnologyEdge"]) {
networkType = @"2.75G EDGE";
}else if ([currentStatus isEqualToString:@"CTRadioAccessTechnologyWCDMA"]){
networkType = @"3G";
}else if ([currentStatus isEqualToString:@"CTRadioAccessTechnologyHSDPA"]){
networkType = @"3.5G HSDPA";
}else if ([currentStatus isEqualToString:@"CTRadioAccessTechnologyHSUPA"]){
networkType = @"3.5G HSUPA";
}else if ([currentStatus isEqualToString:@"CTRadioAccessTechnologyCDMA1x"]){
networkType = @"2G";
}else if ([currentStatus isEqualToString:@"CTRadioAccessTechnologyCDMAEVDORev0"]){
networkType = @"3G";
}else if ([currentStatus isEqualToString:@"CTRadioAccessTechnologyCDMAEVDORevA"]){
networkType = @"3G";
}else if ([currentStatus isEqualToString:@"CTRadioAccessTechnologyCDMAEVDORevB"]){
networkType = @"3G";
}else if ([currentStatus isEqualToString:@"CTRadioAccessTechnologyeHRPD"]){
networkType = @"HRPD";
}else if ([currentStatus isEqualToString:@"CTRadioAccessTechnologyLTE"]){
networkType = @"4G";
} else {
networkType = @"WWAN";
}
}
break;
default:
break;
}
return networkType;
}
+ (void)registerObserveNetWorkStatus{
// 创建Reachability
reachability = [Reachability reachabilityForInternetConnection];
// 开始监控网络(一旦网络状态发生改变,就会发出通知kReachabilityChangedNotification)
[reachability startNotifier];
}
+ (void)unregisterObserveNetWorkStatus{
if (reachability) {
[reachability stopNotifier];
}
}
@end