在 iOS 上检测互联网连接的最简单方法?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/8812459/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 16:13:54  来源:igfitidea点击:

Easiest way to detect Internet connection on iOS?

iosnsurlconnectionreachabilityinternet-connection

提问by RealCasually

I know this question will appear to be a dupe of many others, however, I don't feel the simple case is well explained here. Coming from an Android and BlackBerry background, making requests through HTTPUrlConnectioninstantly fail if there is no connection available. This seems like completely sane behavior, and I was surprised to find NSURLConnectionin iOS did not emulate it.

我知道这个问题似乎会被许多其他问题所欺骗,但是,我觉得这里没有很好地解释这个简单的案例。来自 Android 和 BlackBerry 背景,HTTPUrlConnection如果没有可用连接,则发出请求会立即失败。这似乎是完全理智的行为,我惊讶地发现NSURLConnectioniOS 没有效仿它。

I understand that Apple (and others who have extended it) provide a Reachabilityclass to assist with determining the network state. I was happy to first see this and fully expected to see something like bool isNetworkAvailable(), but instead to my surprise I found a complex system requiring notification registrations and callbacks, and a bunch of seemingly unnecessary details. There must be a better way.

我知道 Apple(以及其他扩展它的人)提供了一个Reachability类来帮助确定网络状态。我很高兴第一次看到这个并完全期待看到类似的东西bool isNetworkAvailable(),但令我惊讶的是,我发现了一个复杂的系统,需要通知注册和回调,以及一堆看似不必要的细节。一定会有更好的办法。

My app already gracefully handles connection failures, including no connectivity. The user is notified of the failure, and the app moves on.

我的应用程序已经优雅地处理连接失败,包括没有连接。用户收到失败通知,应用程序继续运行。

Thus my requirements are simple: Single, synchronous function I can call before all HTTP requests to determine if I should bother actually sending the request or not. Ideally it requires no set up and just returns a boolean.

因此,我的要求很简单:我可以在所有 HTTP 请求之前调用单个同步函数,以确定是否应该打扰实际发送请求。理想情况下,它不需要设置,只返回一个布尔值。

Is this really not possible on iOS?

这在iOS上真的不可能吗?

回答by Semere Taézaz Sium

I did a little more research and I am updating my answer with a more current solution. I am not sure if you have already looked at it but there is a nice sample code provided by Apple.

我做了更多的研究,我正在用更新的解决方案更新我的答案。我不确定您是否已经看过它,但 Apple 提供了一个很好的示例代码。

Download the sample code here

此处下载示例代码

Include the Reachability.h and Reachability.m files in your project. Take a look at ReachabilityAppDelegate.m to see an example on how to determine host reachability, reachability by WiFi, by WWAN etc. For a very simply check of network reachability, you can do something like this

在您的项目中包含 Reachability.h 和 Reachability.m 文件。查看 ReachabilityAppDelegate.m 以查看有关如何确定主机可达性、WiFi 可达性、WWAN 等的示例。对于网络可达性的非常简单的检查,您可以执行以下操作

Reachability *networkReachability = [Reachability reachabilityForInternetConnection];   
NetworkStatus networkStatus = [networkReachability currentReachabilityStatus];    
if (networkStatus == NotReachable) {        
    NSLog(@"There IS NO internet connection");        
} else {        
     NSLog(@"There IS internet connection");        
}

@BenjaminPiette's: Don't forget to add SystemConfiguration.framework to your project.

@BenjaminPiette's:不要忘记将 SystemConfiguration.framework 添加到您的项目中。

回答by sherbertman

Seeing as this thread is the top google result for this type of question, I figured I would provide the solution that worked for me. I was already using AFNetworking, but searching didn't reveal how to accomplish this task with AFNetworking until midway through my project.

鉴于此线程是此类问题的顶级谷歌结果,我想我会提供对我有用的解决方案。我已经在使用AFNetworking,但直到我的项目进行到一半,搜索才揭示如何使用AFNetworking完成这项任务。

What you want is the AFNetworkingReachabilityManager.

你想要的是 AFNetworkingReachabilityManager

// -- Start monitoring network reachability (globally available) -- //
[[AFNetworkReachabilityManager sharedManager] startMonitoring];

[[AFNetworkReachabilityManager sharedManager] setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {

    NSLog(@"Reachability changed: %@", AFStringFromNetworkReachabilityStatus(status));


    switch (status) {
        case AFNetworkReachabilityStatusReachableViaWWAN:
        case AFNetworkReachabilityStatusReachableViaWiFi:
            // -- Reachable -- //
            NSLog(@"Reachable");
            break;
        case AFNetworkReachabilityStatusNotReachable:
        default:
            // -- Not reachable -- //
            NSLog(@"Not Reachable");
            break;
    }

}];

You can also use the following to test reachability synchronously (once monitoring has started):

您还可以使用以下内容同步测试可达性(一旦开始监控):

-(BOOL) isInternetReachable
{
    return [AFNetworkReachabilityManager sharedManager].reachable;
}

回答by dispatchMain

Sorry for replying too late but I hope this answer can help somebody in future.

抱歉回复太晚了,但我希望这个答案将来可以帮助某人。

Following is a small native C code snippet that can check internet connectivity without any extra class.

下面是一个小的原生 C 代码片段,它可以检查互联网连接,而无需任何额外的类。

Add the following headers:

添加以下标题:

#include<unistd.h>
#include<netdb.h>

Code:

代码:

-(BOOL)isNetworkAvailable
{
    char *hostname;
    struct hostent *hostinfo;
    hostname = "google.com";
    hostinfo = gethostbyname (hostname);
    if (hostinfo == NULL){
        NSLog(@"-> no connection!\n");
        return NO;
    }
    else{
        NSLog(@"-> connection established!\n");
        return YES;
    }
}

Swift 3

斯威夫特 3

func isConnectedToInternet() -> Bool {
    let hostname = "google.com"
    //let hostinfo = gethostbyname(hostname)
    let hostinfo = gethostbyname2(hostname, AF_INET6)//AF_INET6
    if hostinfo != nil {
        return true // internet available
      }
     return false // no internet
    }

回答by GilesDMiddleton

I currently use this simple synchronous method which requires no extra files in your projects or delegates.

我目前使用这种简单的同步方法,它不需要您的项目或委托中的额外文件。

Import:

进口:

#import <SystemConfiguration/SCNetworkReachability.h>

Create this method:

创建此方法:

+(bool)isNetworkAvailable
{
    SCNetworkReachabilityFlags flags;
    SCNetworkReachabilityRef address;
    address = SCNetworkReachabilityCreateWithName(NULL, "www.apple.com" );
    Boolean success = SCNetworkReachabilityGetFlags(address, &flags);
    CFRelease(address);

    bool canReach = success
                    && !(flags & kSCNetworkReachabilityFlagsConnectionRequired)
                    && (flags & kSCNetworkReachabilityFlagsReachable);

    return canReach;
}

Then, if you've put this in a MyNetworkClass:

然后,如果你把它放在一个MyNetworkClass

if( [MyNetworkClass isNetworkAvailable] )
{
   // do something networky.
}

If you are testing in the simulator, turn your Mac's wifi on and off, as it appears the simulator will ignore the phone setting.

如果您在模拟器中进行测试,请打开和关闭 Mac 的 wifi,因为模拟器似乎会忽略手机设置。

Update:

更新:

  1. In the end I used a thread/asynchronous callback to avoid blocking the main thread; and regularly re-testing so I could use a cached result - although you should avoid keeping data connections open unnecessarily.

  2. As @thunk described, there are better URLs to use, which Apple themselves use. http://cadinc.com/blog/why-your-apple-ios-7-device-wont-connect-to-the-wifi-network

  1. 最后我使用了线程/异步回调来避免阻塞主线程;并定期重新测试,以便我可以使用缓存的结果 - 尽管您应该避免不必要地保持数据连接打开。

  2. 正如@thunk 所描述的,有更好的 URL 可供使用,Apple 自己使用这些 URL。http://cadinc.com/blog/why-your-apple-ios-7-device-wont-connect-to-the-wifi-network

回答by Danut Pralea

It is possible and it is really simple if you look at it when finishing the implementation, which is again - very simple, since the only items you need are two boolean variables: internet reachability and host reachability (you often need more than one of these). Once you assemble your helper class that can determine the connections status, you really don't care again of the implementation needed for knowing these procedures.

这是可能的,如果您在完成实现时查看它,这真的很简单,这又是 - 非常简单,因为您需要的唯一项目是两个布尔变量:互联网可达性和主机可达性(您通常需要不止一个这些)。一旦您组装了可以确定连接状态的帮助程序类,您就真的不再关心了解这些过程所需的实现。

Example:

例子:

#import <Foundation/Foundation.h>

@class Reachability;

@interface ConnectionManager : NSObject {
    Reachability *internetReachable;
    Reachability *hostReachable;
}

@property BOOL internetActive;
@property BOOL hostActive;

- (void) checkNetworkStatus:(NSNotification *)notice;

@end

And the .m file:

和 .m 文件:

#import "ConnectionManager.h"
#import "Reachability.h"

@implementation ConnectionManager
@synthesize internetActive, hostActive;

-(id)init {
    self = [super init];
    if(self) {

    }
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(checkNetworkStatus:) name:kReachabilityChangedNotification object:nil];

    internetReachable = [[Reachability reachabilityForInternetConnection] retain];
    [internetReachable startNotifier];

    hostReachable = [[Reachability reachabilityWithHostName:@"www.apple.com"] retain];
    [hostReachable startNotifier];

    return self;
}

- (void) checkNetworkStatus:(NSNotification *)notice {
    NetworkStatus internetStatus = [internetReachable currentReachabilityStatus];
    switch (internetStatus)

    {
        case NotReachable:
        {
            NSLog(@"The internet is down.");
            self.internetActive = NO;

            break;

        }
        case ReachableViaWiFi:
        {
            NSLog(@"The internet is working via WIFI.");
            self.internetActive = YES;

            break;

        }
        case ReachableViaWWAN:
        {
            NSLog(@"The internet is working via WWAN.");
            self.internetActive = YES;

            break;

        }
    }

    NetworkStatus hostStatus = [hostReachable currentReachabilityStatus];
    switch (hostStatus)

    {
        case NotReachable:
        {
            NSLog(@"A gateway to the host server is down.");
            self.hostActive = NO;

            break;

        }
        case ReachableViaWiFi:
        {
            NSLog(@"A gateway to the host server is working via WIFI.");
            self.hostActive = YES;

            break;

        }
        case ReachableViaWWAN:
        {
            NSLog(@"A gateway to the host server is working via WWAN.");
            self.hostActive = YES;

            break;

        }
    }

}

// If lower than SDK 5 : Otherwise, remove the observer as pleased.

- (void)dealloc {
    [[NSNotificationCenter defaultCenter] removeObserver:self];
    [super dealloc];
}

@end

回答by Danut Pralea

Someone hassolved this in a simple, reusable way before. DDGReachability.

以前有人用一种简单的、可重用的方式解决了这个问题。DDGReachability.

EDIT: Or tonymillion/Reachability.

编辑:或者tonymillion/Reachability

回答by Walty Yeung

I extracted the code and put into one single method, hope it would help others.

我提取了代码并将其放入一个方法中,希望对其他人有所帮助。

#import <SystemConfiguration/SystemConfiguration.h>

#import <netinet/in.h>
#import <netinet6/in6.h>

...

...

- (BOOL)isInternetReachable
{    
    struct sockaddr_in zeroAddress;
    bzero(&zeroAddress, sizeof(zeroAddress));
    zeroAddress.sin_len = sizeof(zeroAddress);
    zeroAddress.sin_family = AF_INET;

    SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (const struct sockaddr*)&zeroAddress);
    SCNetworkReachabilityFlags flags;

    if(reachability == NULL)
        return false;

    if (!(SCNetworkReachabilityGetFlags(reachability, &flags)))
        return false;

    if ((flags & kSCNetworkReachabilityFlagsReachable) == 0)
        // if target host is not reachable
        return false;


    BOOL isReachable = false;


    if ((flags & kSCNetworkReachabilityFlagsConnectionRequired) == 0)
    {
        // if target host is reachable and no connection is required
        //  then we'll assume (for now) that your on Wi-Fi
        isReachable = true;
    }


    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
            isReachable = true;
        }
    }

    if ((flags & kSCNetworkReachabilityFlagsIsWWAN) == kSCNetworkReachabilityFlagsIsWWAN)
    {
        // ... but WWAN connections are OK if the calling application
        //     is using the CFNetwork (CFSocketStream?) APIs.
        isReachable = true;
    }


    return isReachable;


}

回答by pooja

I think this could help..

我认为这可以帮助..

[[AFNetworkReachabilityManager sharedManager] startMonitoring];

if([AFNetworkReachabilityManager sharedManager].isReachable)
{
    NSLog(@"Network reachable");
}
else
{   
   NSLog(@"Network not reachable");
}

回答by Satyen Udeshi

I am writing the swift version of the accepted answer here, incase if someone finds it usefull, the code is written swift 2,

我正在此处编写已接受答案的 swift 版本,以防万一有人觉得它有用,代码将编写为 swift 2,

You can download the required files from SampleCode

您可以从SampleCode下载所需的文件

Add Reachability.hand Reachability.mfile to your project,

添加Reachability.hReachability.m归档到您的项目中,

Now one will need to create Bridging-Header.hfile if none exists for your project,

现在,Bridging-Header.h如果您的项目不存在文件,则需要创建文件,

Inside your Bridging-Header.hfile add this line :

在您的Bridging-Header.h文件中添加这一行:

#import "Reachability.h"

Now in order to check for Internet Connection

现在为了检查 Internet 连接

static func isInternetAvailable() -> Bool {
    let networkReachability : Reachability = Reachability.reachabilityForInternetConnection()
    let networkStatus : NetworkStatus = networkReachability.currentReachabilityStatus()

    if networkStatus == NotReachable {
        print("No Internet")
        return false
    } else {
        print("Internet Available")
        return true
    }

}

回答by Ravi Raja Jangid

You may also try this one if you already configured AFNetworking in your project.

如果你已经在你的项目中配置了 AFNetworking,你也可以试试这个。

-(void)viewDidLoad{  // -- add connectivity notification --//
[[NSNotificationCenter defaultCenter ] addObserver:self selector:@selector(ReachabilityDidChangeNotification:) name:AFNetworkingReachabilityDidChangeNotification object:nil];}
-(void)ReachabilityDidChangeNotification:(NSNotification *)notify
{
// -- NSLog(@"Reachability changed: %@", AFStringFromNetworkReachabilityStatus(status));  -- //
NSDictionary *userInfo =[notif userInfo];
AFNetworkReachabilityStatus status= [[userInfo valueForKey:AFNetworkingReachabilityNotificationStatusItem] intValue];
switch (status)
{
    case AFNetworkReachabilityStatusReachableViaWWAN:
    case AFNetworkReachabilityStatusReachableViaWiFi:
        // -- Reachable -- //
// -- Do your stuff when internet connection is available -- //
        [self getLatestStuff];
        NSLog(@"Reachable");
        break;
    case AFNetworkReachabilityStatusNotReachable:
    default:
        // -- Not reachable -- //
        // -- Do your stuff for internet connection not available -- //
NSLog(@"Not Reachable");
        break;
}
}