监听网络状态的改变

来源:互联网 发布:excel数据提取工具 编辑:程序博客网 时间:2024/05/19 00:53

监听网络状态

//这是一个已经封装好的监听网络状态的文件,直接拖进来使用就行了//Reachability.h#import <Foundation/Foundation.h>#import <SystemConfiguration/SystemConfiguration.h>#import <netinet/in.h>typedef enum : NSInteger {    NotReachable = 0, // 没有连接    ReachableViaWiFi, // 通过 WiFi 连接    ReachableViaWWAN  // 通过 2G/3G/4G 连接} NetworkStatus;extern NSString *kReachabilityChangedNotification;@interface Reachability : NSObject/*! 检测能否连接到指定的主机 * Use to check the reachability of a given host name. */+ (instancetype)reachabilityWithHostName:(NSString *)hostName;/*! 检测能否连接到指定的 IP 地址 * 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;/*! 检查本地 wifi 是否可用 * Checks whether a local WiFi connection is available. */+ (instancetype)reachabilityForLocalWiFi;/*! 开始在当前运行循环监听网络连接通知 * Start listening for reachability notifications on the current run loop. */- (BOOL)startNotifier;/** *  停止监听器 */- (void)stopNotifier;/** *  当前连接状态 * *  @return 网络状态 */- (NetworkStatus)currentReachabilityStatus;/*! 是否需要连接 WWAN 在连接建立之前不能使用 Wi-Fi 通过 VPN 连接 * 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",          (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];}#pragma mark - Reachability implementation@implementation Reachability{    BOOL _alwaysReturnLocalWiFiStatus; //default is NO    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;            returnValue->_alwaysReturnLocalWiFiStatus = NO;        }    }    return returnValue;}+ (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];}+ (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};    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
  • 主控制器文件
//ViewController.h#import <UIKit/UIKit.h>@interface ViewController : UIViewController@end
//ViewController.m#import "ViewController.h"#import "Reachability.h"@interface ViewController ()@property (nonatomic, strong) Reachability *reachablityManager;@end@implementation ViewController- (void)dealloc {    // 移除通知    [[NSNotificationCenter defaultCenter] removeObserver:self];    // 移除监听网络状态    [self.reachablityManager stopNotifier];}- (void)viewDidLoad {    [super viewDidLoad];    // 监听网络状态通知    [[NSNotificationCenter defaultCenter ] addObserver:self selector:@selector(networkStatusChanged) name:kReachabilityChangedNotification object:nil];    // 开始监听(这里可以理解为让RunLoop来监听网络状态,当监听的网络状态改变时,会对外发出kReachabilityChangedNotification通知)    [self.reachablityManager startNotifier];}//手动点击来刷新网络状态(可不要)- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {    [self networkStatusChanged];}/** *  网络状态改变的回调方法 */- (void)networkStatusChanged {    // 获得当前的网络状态    NetworkStatus status = [self.reachablityManager currentReachabilityStatus];    switch (status) {        case NotReachable:            NSLog(@"木有连接,没有网络");            break;        case ReachableViaWiFi:            NSLog(@"wifi,不用钱,尽管用");            break;        case ReachableViaWWAN:            NSLog(@"3G/4G,要钱,土豪随意");            break;    }}- (Reachability *)reachablityManager {    if (_reachablityManager == nil) {        // 在实际开发中,填写公司的服务器域名        _reachablityManager = [Reachability reachabilityWithHostName:@"baidu.com"];    }    return _reachablityManager;}@end
0 0
原创粉丝点击