zoukankan      html  css  js  c++  java
  • 李洪强iOS开发之使用 Reachability 检测网络

    1.iOS平台是按照一直有网络连接的思路来设计的,开发者利用这一特点创造了很多优秀的第三方应用。

    大多数的iOS应用都需要联网,甚至有些应用严重依赖网络,没有网络就无法正常工作。

    2.在你的应用尝试通过网络获取数据之前,你需要知道当前设备是否知道连接上了网络,

    甚至有时候你可能还需要知道当前网路是由wifi还是由移动蜂窝网络提供的。

    3.“在网络访问失败的时候,应用没有做出适当的提示”是苹果的iOS审核团队拒绝一个应用的常见理由。

    苹果要求你必须先检测网络连接状态,当网络不可用的时候以某种方式告知用户,或者用其他优雅的方式进行处理。

     

    ***********************

    Reachability类:

    1.这个类用于检测当前网络状态,它不是SDK的一部分,可以在iOS Developer Library里找到这份代码。

    从苹果网站上下载Reachability.zip文件,解压之。

    2.重用Reachability类

        (1)把Reachability.h和Reachability.m文件拖到项目中。

        (2)添加框架:SystemConfiguration.framework。

    3.同步的Reachability

        (1)使用同步的方式是比较简单,导入Reachability.h头文件,然后通过代码检查网络:

            #import “Reachability.h”

            。。。some code omitted…

            Reachability *reach = [Reachability reachabilityForInternetConnection];

            NetworkStatus status = [reach currentReachabilityStatus];

         (2)通过检查某个主机能否访问来判断当前网络是否可用:

            Reachability *reach = [Reachability reachabilityWithHostName:@“www.apple.com”];

            NetworkStatus status = [reach currentReachabilityStatus];

         (3)案例:

            创建一个工程,并添加Reachability.h和Reachability.m到工程中,并链接SystemConfiguration.framework.

            在AppDelegate.h头文件中导入Reachability.h,并添加一个实例方法。如图:

                    

            在AppDelegate.m中这样实现:如图:

                

            

    4.异步的Reachability

        (1)异步的方式稍微复杂,不过通过这种方式可以来订阅实时的网络状态变化通知。导入Reachability.h头文件,然后注册一个对象来订阅网络状态变化的信息,网络状态变化的信息名称为kReachabilityChanged-Notification.如下:

        [[NSNotificationCenter defaultCenter] addObserver:self

            selector:@selector(reachabilityChanged:)

            name:kReachabilityChangedNotification

            object:nil];

        (2)你需要创建一个Reachability对象实例并开始向外发布网络状态变化的消息:

            Reachability *reach = [[Reachability reachabilityWithHostName:@“www.apple.com”] retain];

            [reach startNotifier];

        (3)当网络状态发生变化的时候,Reachability对象将调用reachabilityChanged:方法,可以在这个方法里面获取当前的网络状态,然后做相应的处理。

            - (void)reachabilityChanged:(NSNotification *)notification{

                Reachability *reach = [notification object];

                if([reach isKindOfClass:[Reachability class]]){

                    NetworkStatus status = [reach currentReachabilityStatus];

                    //Insert your code here

                }                   

            }

     

    ****************************

    5.原生 Reachability API

    前面将的Reachability类实际上是苹果公司对SCNetworkReachability API的封装,这个API定义在SystemConfigure.framework库中。如果有其他特别的需求,也可以直接使用这个原生的SCNetworkReachability类。 

     .h 和.m文件

     //-------------------------.m---------------------------------------------------

     //-------------------------.m---------------------------------------------------

     

     

    /*

         File: Reachability.h

     

     Copyright (C) 2014 Apple Inc. All Rights Reserved.

     

     */

     

    #import <Foundation/Foundation.h>

    #import <SystemConfiguration/SystemConfiguration.h>

    #import <netinet/in.h>

     

     

    typedef enum : NSInteger {

    NotReachable = 0,

    ReachableViaWiFi,

    ReachableViaWWAN

    } NetworkStatus;

     

     

    extern NSString *kReachabilityChangedNotification;

     

     

    @interface Reachability : NSObject

     

    /*!

     *

     用于检查给定主机名的可达性。

     */

    + (instancetype)reachabilityWithHostName:(NSString *)hostName;

     

    /*!

     *

     用来检查给定IP地址的可达性。

     */

    + (instancetype)reachabilityWithAddress:(const struct sockaddr_in *)hostAddress;

     

    /*!

     *

     检查是否违约路is availableshould be used by应用that do not connect to a particular主机。

     */

    + (instancetype)reachabilityForInternetConnection;

     

    /*!

     * 检查是否一个本地无线连接是可用的。

     */

    + (instancetype)reachabilityForLocalWiFi;

     

    /*!

     *开始在当前运行的循环上侦听可达性通知。

     */

    - (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.

     *广域网可能是可用的,但不主动到连接已经建立。无线网络可能需要连接VPN的需求。

     */

    - (BOOL)connectionRequired;

     

    @end

     //-------------------------.m---------------------------------------------------

     //-------------------------.m---------------------------------------------------

    /*

         File: Reachability.m

     Abstract: Basic demonstration of how to use the SystemConfiguration Reachablity APIs.

      Version: 3.5

     

     Copyright (C) 2014 Apple Inc. All Rights Reserved.

     

     */

     

    #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 ",

              (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

     

     

     

     

  • 相关阅读:
    Solaris 默认Shell 修改
    关系数组
    文件描述符 文件操作 <> open 文件句柄
    IO 双引号 输出 输入
    第五章答案
    子例程 subroutine
    钻石操作符
    花括号的使用 printf %${width}s , 否则会 去找 $widths
    print reverse <> 是打印全部的文件内容 ?
    hihoCoder#1239 Fibonacci
  • 原文地址:https://www.cnblogs.com/LiLihongqiang/p/5669687.html
Copyright © 2011-2022 走看看