李洪強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\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

 

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM