• 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
    ",
              //当前网络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];  
  • 相关阅读:
    【LeetCode】【动态规划】Edit Distance
    【LeetCode】最大子阵列 Maximum Subarray(贪婪&分治)
    【LeetCode】【矩阵旋转】Rotate Image
    解决Torch.load()错误信息: UnicodeDecodeError: 'ascii' codec can't decode byte 0x8d in position 0: ordinal not in range(128)
    使用VS Code配合Remote Development插件连接远程服务器(Mac/Linux+Windows) | Using VS Code with Remote Development Connect to Remote Server (Mac/Linux+Windows)
    Leaflet入门:添加点线面并导入GeoJSON数据|Tutorial of Leaflet: Adding Points, Lines, Polygons and Import GeoJSON File
    使用Adobe Illustrator + ArcGIS绘制地图 | Map Design Using ArcGIS + Adobe Illustrator
    PostgreSQL 速查、备忘手册 | PostgreSQL Quick Find and Tutorial
    LIRE教程之源码分析 | LIRE Tutorial of Analysis of the Source Code
    解决Tomcat错误信息:No 'Access-Control-Allow-Origin' header is present on the requested resource | Solving Tomcat Error: No 'Access-Control-Allow-Origin' header is present on the requested resource
  • 原文地址:https://www.cnblogs.com/xiaofeixiang/p/4472343.html
Copyright © 2020-2023  润新知