How can I check for an active Internet connection on iOS or macOS? – Dev

The best answers to the question “How can I check for an active Internet connection on iOS or macOS?” in the category Dev.

QUESTION:

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

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.

- (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 stringWithContentsOfURL is deprecated in iOS 3.0 and macOS 10.4) and if so, what is a better way to accomplish this?

ANSWER:

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.

ANSWER:

Important: This check should always be 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

  2. Test reachability via closures

    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

  1. Add SystemConfiguration framework to the project but don’t worry about including it anywhere

  2. Add Tony Million’s version of Reachability.h and Reachability.m to the project (found here: https://github.com/tonymillion/Reachability)

  3. Update the interface section

    #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

    // 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 Reachability class 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.h and Reachability.m files to something else to resolve the issue.

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

ANSWER:

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:

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.

ANSWER:

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

Include the SystemConfiguration.framework in your project.

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 5 tested for you.