如何在 iOS 或 macOS 上检查活动的互联网连接?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1083701/
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:07:32  来源:igfitidea点击:

How to check for an active Internet connection on iOS or macOS?

iosmacoscocoacocoa-touchreachability

提问by Brock Woolf

I would like to check to see if I have an Internet connection on iOS using the Cocoa Touchlibraries or on macOS using the Cocoalibraries.

我想检查一下我是否在使用Cocoa Touch库的iOS或使用Cocoa库的macOS上有互联网连接。

I came up with a way to do this using an NSURL. The way I did it seems a bit unreliable (because even Google could one day be down and relying on a third party seems bad), and while I could check to see for a response from some other websites if Google didn't respond, it does seem wasteful and an unnecessary overhead on my application.

我想出了一种使用NSURL. 我这样做的方式似乎有点不可靠(因为即使有一天谷歌可能会宕机并且依赖第三方似乎很糟糕),虽然如果谷歌没有回应,我可以查看其他一些网站的回应,它对我的应用程序来说似乎是浪费和不必要的开销。

- (BOOL) connectedToInternet
{
    NSString *URLString = [NSString stringWithContentsOfURL:[NSURL URLWithString:@"http://www.google.com"]];
    return ( URLString != NULL ) ? YES : NO;
}

Is what I have done bad, (not to mention stringWithContentsOfURLis deprecated in iOS 3.0 and macOS 10.4) and if so, what is a better way to accomplish this?

我做的不好(更不用说stringWithContentsOfURL在 iOS 3.0 和 macOS 10.4 中已弃用),如果是这样,有什么更好的方法来实现这一目标?

采纳答案by iwasrobbed

Important: This check should alwaysbe performed asynchronously. The majority of answers below are synchronous so be careful otherwise you'll freeze up your app.

重要提示:此检查应始终异步执行。下面的大多数答案都是同步的,所以要小心,否则你会冻结你的应用程序。



Swift

迅速

1) Install via CocoaPods or Carthage: https://github.com/ashleymills/Reachability.swift

1) 通过 CocoaPods 或 Carthage 安装:https: //github.com/ashleymills/Reachability.swift

2) Test reachability via closures

2) 通过闭包测试可达性

let reachability = Reachability()!

reachability.whenReachable = { reachability in
    if reachability.connection == .wifi {
        print("Reachable via WiFi")
    } else {
        print("Reachable via Cellular")
    }
}

reachability.whenUnreachable = { _ in
    print("Not reachable")
}

do {
    try reachability.startNotifier()
} catch {
    print("Unable to start notifier")
}


Objective-C

目标-C

1) Add SystemConfigurationframework to the project but don't worry about including it anywhere

1)将SystemConfiguration框架添加到项目中,但不要担心将其包含在任何地方

2) Add Tony Million's version of Reachability.hand Reachability.mto the project (found here: https://github.com/tonymillion/Reachability)

2) 将 Tony Million 的Reachability.h和版本添加Reachability.m到项目中(在此处找到:https: //github.com/tonymillion/Reachability

3) Update the interface section

3)更新界面部分

#import "Reachability.h"

// Add this to the interface in the .m file of your view controller
@interface MyViewController ()
{
    Reachability *internetReachableFoo;
}
@end

4) Then implement this method in the .m file of your view controller which you can call

4) 然后在你可以调用的视图控制器的 .m 文件中实现这个方法

// Checks if we have an internet connection or not
- (void)testInternetConnection
{   
    internetReachableFoo = [Reachability reachabilityWithHostname:@"www.google.com"];

    // Internet is reachable
    internetReachableFoo.reachableBlock = ^(Reachability*reach)
    {
        // Update the UI on the main thread
        dispatch_async(dispatch_get_main_queue(), ^{
            NSLog(@"Yayyy, we have the interwebs!");
        });
    };

    // Internet is not reachable
    internetReachableFoo.unreachableBlock = ^(Reachability*reach)
    {
        // Update the UI on the main thread
        dispatch_async(dispatch_get_main_queue(), ^{
            NSLog(@"Someone broke the internet :(");
        });
    };

    [internetReachableFoo startNotifier];
}

Important Note:The Reachabilityclass is one of the most used classes in projects so you might run into naming conflicts with other projects. If this happens, you'll have to rename one of the pairs of Reachability.hand Reachability.mfiles to something else to resolve the issue.

重要提示:Reachability类是最常用的类别中的一个项目,所以你可能会遇到的命名与其他项目冲突。如果发生这种情况,您必须将Reachability.hReachability.m文件对中的一个重命名为其他名称以解决问题。

Note:The domain you use doesn't matter. It's just testing for a gateway to any domain.

注意:您使用的域无关紧要。它只是测试通往任何域的网关。

回答by cannyboy

I like to keep things simple. The way I do this is:

我喜欢保持简单。我这样做的方法是:

//Class.h
#import "Reachability.h"
#import <SystemConfiguration/SystemConfiguration.h>

- (BOOL)connected;

//Class.m
- (BOOL)connected
{
    Reachability *reachability = [Reachability reachabilityForInternetConnection];
    NetworkStatus networkStatus = [reachability currentReachabilityStatus];
    return networkStatus != NotReachable;
}

Then, I use this whenever I want to see if I have a connection:

然后,每当我想查看是否有连接时,我都会使用它:

if (![self connected]) {
    // Not connected
} else {
    // Connected. Do some Internet stuff
}

This method doesn't wait for changed network statuses in order to do stuff. It just tests the status when you ask it to.

此方法不会等待更改的网络状态来执行操作。它只是在您要求时测试状态。

回答by Andrew Zimmer

Using Apple's Reachability code, I created a function that'll check this correctly without you having to include any classes.

使用 Apple 的 Reachability 代码,我创建了一个函数,它可以正确检查这一点,而无需包含任何类。

Include the SystemConfiguration.framework in your project.

在您的项目中包含 SystemConfiguration.framework。

Make some imports:

做一些进口:

#import <sys/socket.h>
#import <netinet/in.h>
#import <SystemConfiguration/SystemConfiguration.h>

Now just call this function:

现在只需调用此函数:

/*
Connectivity testing code pulled from Apple's Reachability Example: https://developer.apple.com/library/content/samplecode/Reachability
 */
+(BOOL)hasConnectivity {
    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);
    if (reachability != NULL) {
        //NetworkStatus retVal = NotReachable;
        SCNetworkReachabilityFlags flags;
        if (SCNetworkReachabilityGetFlags(reachability, &flags)) {
            if ((flags & kSCNetworkReachabilityFlagsReachable) == 0)
            {
                // If target host is not reachable
                return NO;
            }

            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
                return YES;
            }


            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
                    return YES;
                }
            }

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

    return NO;
}

And it's iOS 5tested for you.

它是为您测试的iOS 5

回答by Daniel Rinser

This used to be the correct answer, but it is now outdated as you should subscribe to notifications for reachability instead. This method checks synchronously:

这曾经是正确的答案,但现在已经过时了,因为您应该订阅可访问性通知。此方法同步检查:



You can use Apple's Reachability class. It will also allow you to check if Wi-Fi is enabled:

您可以使用 Apple 的 Reachability 类。它还允许您检查是否启用了 Wi-Fi:

Reachability* reachability = [Reachability sharedReachability];
[reachability setHostName:@"www.example.com"];    // Set your host name here
NetworkStatus remoteHostStatus = [reachability remoteHostStatus];

if (remoteHostStatus == NotReachable) { }
else if (remoteHostStatus == ReachableViaWiFiNetwork) { }
else if (remoteHostStatus == ReachableViaCarrierDataNetwork) {?}

The Reachability class is not shipped with the SDK, but rather a part of this Apple sample application. Just download it, and copy Reachability.h/m to your project. Also, you have to add the SystemConfiguration framework to your project.

Reachability 类未随 SDK 一起提供,而是此 Apple 示例应用程序的一部分。只需下载它,然后将 Reachability.h/m 复制到您的项目中。此外,您必须将 SystemConfiguration 框架添加到您的项目中。

回答by Erik

Here's a very simple answer:

这是一个非常简单的答案:

NSURL *scriptUrl = [NSURL URLWithString:@"http://www.google.com/m"];
NSData *data = [NSData dataWithContentsOfURL:scriptUrl];
if (data)
    NSLog(@"Device is connected to the Internet");
else
    NSLog(@"Device is not connected to the Internet");

The URL should point to an extremely small website. I use Google's mobile website here, but if I had a reliable web server I'd upload a small file with just one character in itfor maximum speed.

URL 应该指向一个非常小的网站。我在这里使用谷歌的移动网站,但如果我有一个可靠的网络服务器,我会上传一个只有一个字符的小文件以获得最大速度。

If checking whether the device is somehowconnected to the Internet is everything you want to do, I'd definitely recommend using this simple solution. If you need to know how the user is connected, using Reachability is the way to go.

如果检查设备是否以某种方式连接到 Internet 是您想做的一切,我绝对建议您使用这个简单的解决方案。如果您需要知道用户是如何连接的,那么使用 Reachability 是一种可行的方法。

Careful: This will briefly block your thread while it loads the website. In my case, this wasn't a problem, but you should consider this (credits to Brad for pointing this out).

小心:这将在加载网站时暂时阻止您的线程。就我而言,这不是问题,但您应该考虑这一点(感谢 Brad 指出这一点)。

回答by klcjr89

Here is how I do it in my apps: While a 200 status response code doesn't guarantee anything, it is stable enough for me. This doesn't require as much loading as the NSData answers posted here, as mine just checks the HEAD response.

以下是我在我的应用程序中的做法:虽然 200 状态响应代码并不能保证任何事情,但它对我来说已经足够稳定了。这不需要像此处发布的 NSData 答案那样多的加载,因为我的只是检查 HEAD 响应。

Swift Code

SWIFT代码

func checkInternet(flag:Bool, completionHandler:(internet:Bool) -> Void)
{
    UIApplication.sharedApplication().networkActivityIndicatorVisible = true

    let url = NSURL(string: "http://www.google.com/")
    let request = NSMutableURLRequest(URL: url!)

    request.HTTPMethod = "HEAD"
    request.cachePolicy = NSURLRequestCachePolicy.ReloadIgnoringLocalAndRemoteCacheData
    request.timeoutInterval = 10.0

    NSURLConnection.sendAsynchronousRequest(request, queue:NSOperationQueue.mainQueue(), completionHandler:
    {(response: NSURLResponse!, data: NSData!, error: NSError!) -> Void in

        UIApplication.sharedApplication().networkActivityIndicatorVisible = false

        let rsp = response as! NSHTTPURLResponse?

        completionHandler(internet:rsp?.statusCode == 200)
    })
}

func yourMethod()
{
    self.checkInternet(false, completionHandler:
    {(internet:Bool) -> Void in

        if (internet)
        {
            // "Internet" aka Google URL reachable
        }
        else
        {
            // No "Internet" aka Google URL un-reachable
        }
    })
}

Objective-C Code

Objective-C 代码

typedef void(^connection)(BOOL);

- (void)checkInternet:(connection)block
{
    NSURL *url = [NSURL URLWithString:@"http://www.google.com/"];
    NSMutableURLRequest *headRequest = [NSMutableURLRequest requestWithURL:url];
    headRequest.HTTPMethod = @"HEAD";

    NSURLSessionConfiguration *defaultConfigObject = [NSURLSessionConfiguration ephemeralSessionConfiguration];
    defaultConfigObject.timeoutIntervalForResource = 10.0;
    defaultConfigObject.requestCachePolicy = NSURLRequestReloadIgnoringLocalAndRemoteCacheData;

    NSURLSession *defaultSession = [NSURLSession sessionWithConfiguration:defaultConfigObject delegate:self delegateQueue: [NSOperationQueue mainQueue]];

    NSURLSessionDataTask *dataTask = [defaultSession dataTaskWithRequest:headRequest
        completionHandler:^(NSData *data, NSURLResponse *response, NSError *error)
    {
        if (!error && response)
        {
            block([(NSHTTPURLResponse *)response statusCode] == 200);
        }
    }];
    [dataTask resume];
}

- (void)yourMethod
{
    [self checkInternet:^(BOOL internet)
    {
         if (internet)
         {
             // "Internet" aka Google URL reachable
         }
         else
         {
             // No "Internet" aka Google URL un-reachable
         }
    }];
}

回答by teabot

Apple supplies sample codeto check for different types of network availability. Alternatively there is an examplein the iPhone developers cookbook.

Apple 提供示例代码来检查不同类型的网络可用性。或者,iPhone 开发人员手册中有一个示例

Note:Please see @KHG's comment on this answer regarding the use of Apple's reachability code.

注意:请参阅@KHG 对此答案的评论,有关 Apple 的可达性代码的使用。

回答by Aleksander Azizi

You could use Reachabilityby ? (available here).

你可以用Reachability? (可在此处获得)。

#import "Reachability.h"

- (BOOL)networkConnection {
    return [[Reachability reachabilityWithHostName:@"www.google.com"] currentReachabilityStatus];
}

if ([self networkConnection] == NotReachable) { /* No Network */ } else { /* Network */ } //Use ReachableViaWiFi / ReachableViaWWAN to get the type of connection.

回答by Aleksander Azizi

Apple provides a sample app which does exactly this:

Apple 提供了一个示例应用程序,它正是这样做的:

Reachability

可达性

回答by Ben Groot

Only the Reachability class has been updated. You can now use:

只有 Reachability 类已更新。您现在可以使用:

Reachability* reachability = [Reachability reachabilityWithHostName:@"www.apple.com"];
NetworkStatus remoteHostStatus = [reachability currentReachabilityStatus];

if (remoteHostStatus == NotReachable) { NSLog(@"not reachable");}
else if (remoteHostStatus == ReachableViaWWAN) { NSLog(@"reachable via wwan");}
else if (remoteHostStatus == ReachableViaWiFi) { NSLog(@"reachable via wifi");}