iOS实现实时检测网络状态的示例代码

前言

在网络应用中,需要对用户设备的网络状态进行实时监控,有两个目的:

(1)让用户了解自己的网络状态,防止一些误会(比如怪应用无能)

(2)根据用户的网络状态进行智能处理,节省用户流量,提高用户体验

  WIFI\3G网络:自动下载高清图片

  低速网络:只下载缩略图

  没有网络:只显示离线的缓存数据

最近在工作中遇到一个功能就是根据用户当前的网络状,用户未联网需要提示一下,如果是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 voidvoid *)(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;
 }
} 

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对我们的支持。

(0)

相关推荐

  • iOS 检测网络状态的两种方法

    一般有两种方式,都是第三方的框架,轮子嘛,能用就先用着,后面再优化. 一:Reachability 1.首先在AppDelegate.h添加头文件"Reachability.h",导入框架SystemConfiguration.frame. 2. 在AppDelegate.m中这样实现: - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launc

  • iOS实时监控网络状态的改变

    在网络应用中,有的时候需要对用户设备的网络状态进行实时监控,有两个目的:  (1)让用户了解自己的网络状态,防止一些误会(比如怪应用无能)  (2)根据用户的网络状态进行智能处理,节省用户流量,提高用户体验  WIFI网络:自动下载高清图片  4G/3G网络:只下载缩略图  没有网络:只显示离线的缓存数据  常用的有以下两种方法:  (1).使用苹果观法提供的检测iOS设备网络环境用的库 Reachablity  (2).使用AFN框架中的AFNetworkReachabilityManager

  • iOS实现实时检测网络状态的示例代码

    前言 在网络应用中,需要对用户设备的网络状态进行实时监控,有两个目的: (1)让用户了解自己的网络状态,防止一些误会(比如怪应用无能) (2)根据用户的网络状态进行智能处理,节省用户流量,提高用户体验 WIFI\3G网络:自动下载高清图片 低速网络:只下载缩略图 没有网络:只显示离线的缓存数据 最近在工作中遇到一个功能就是根据用户当前的网络状,用户未联网需要提示一下,如果是Wifi可以推荐一些图片新闻,如果是3G模式设置为无图的模式,获取网络状态比较简单,毕竟中国现在的流量还是一个比较贵的状态,

  • iOS 12+ 中检测网络访问的方法

    我最近写了一篇文章,来介绍 iOS 在连接新的 Wi-Fi 网络时,如何在弹出一个 web view 以让用户登录或注册之前,检测 Captive Portals (强制网络门户).如果你连接过诸如酒店.酒吧或咖啡店等地的公共 Wi-Fi 网络,对这个应该会比较熟悉.如果你不熟悉 iOS 中 Captive Portals 的工作方式,可以查看 Solving the Captive Portal Problem on iOS 这篇文章,以了解一些背景知识. 多年来,Apple 的 Reacha

  • python实时检测键盘输入函数的示例

    在嵌入式.尤其是机器人的python编程中,经常需要实时检测用户的键盘输入来随时控制机器人,这段代码可以帮助我们提取用户输入的字符,并在按下键盘的时候作出反应. import sys import tty import termios def readchar(): fd = sys.stdin.fileno() old_settings = termios.tcgetattr(fd) try: tty.setraw(sys.stdin.fileno()) ch = sys.stdin.read

  • Python实现定时检测网站运行状态的示例代码

    通过定时的检测网站的状态,通常检测地址为网站的域名,如果链接的状态码不是200,那么,就将对其进行下线处理,在特定时间后对其进行二次探测状态,如果符合将其上线,以前使用的创宇云的监控,但是功能比较单一,无法满足需求,近期使用Python来实现这一功能,后期将编写监控模块,并进行代码开源或搭建公共服务器. 本次抒写的是链接状态码获取,可以一应用在网站监控,友情链接监控等方面,及时作出提醒预警.状态处理等,方便网站优化.本次使用了python的requests.datatime.BlockingSc

  • go语言实现并发网络爬虫的示例代码

    go语言做爬虫也是很少尝试,首先我的思路是看一下爬虫的串行实现,然后通过两个并发实现:一个使用锁,另一个使用通道 这里不涉及从页面中提取URL的逻辑(请查看Go框架colly的内容).网络抓取只是作为一个例子来考察Go的并发性. 我们想从我们的起始页中提取所有的URL,将这些URL保存到一个列表中,然后对列表中的每个URL做同样的处理.页面的图很可能是循环的,所以我们需要记住哪些页面已经经历了这个过程(或者在使用并发时,处于这个过程的中间). 串行爬虫首先检查我们是否已经在获取地图中获取了该页面

  • IOS获取系统相册中照片的示例代码

    先来看看效果图 下面话不多少,我们直接上代码: #import "ViewController.h" @interface ViewController ()<UINavigationControllerDelegate,UIImagePickerControllerDelegate> @property (weak, nonatomic) IBOutlet UIImageView *IconView; @end @implementation ViewController

  • JS实现点击复选框变更DIV显示状态的示例代码

    首先是页面上: <div class="row cl"> <label class="form-label col-xs-4 col-sm-3" style="width: 20%"><span class="c-red">*</span>是否存在促销活动:</label> <div class="formControls col-xs-8 col-s

  • Python 使用Opencv实现目标检测与识别的示例代码

    在上章节讲述到图像特征检测与匹配 ,本章节是讲述目标检测与识别.后者是在前者的基础上进一步完善. 在本章中,我们使用HOG算法,HOG和SIFT.SURF同属一种类型的描述符.功能代码如下: import cv2 def is_inside(o, i): ox, oy, ow, oh = o ix, iy, iw, ih = i # 如果符合条件,返回True,否则返回False return ox > ix and oy > iy and ox + ow < ix + iw and o

随机推荐