Easiest Way to Detect Internet Connection on Ios

Easiest way to detect Internet connection on iOS?

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.

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

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

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.

iOS: How to test Internet connection in the most easy way, without freezing the app (without Reachability)?

Nayem is right - you should wrap the third option (async network check) in a class method like this:

+ (void)checkInternetConnectivityWithSuccessCompletion:(void (^)(void))completion {

NSOperationQueue *myQueue = [[NSOperationQueue alloc] init];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:@"https://www.google.com"]];
request.timeoutInterval = 10;

[NSURLConnection sendAsynchronousRequest:request queue:myQueue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error)
{
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) response;
NSLog(@"response status code: %ld, error status : %@", (long)[httpResponse statusCode], error.description);

if ((long)[httpResponse statusCode] >= 200 && (long)[httpResponse statusCode]< 400)
{
// do stuff
NSLog(@"Connected!");
completion();
}
else
{
NSLog(@"Not connected!");
}
}];
}

And then call the method like this:

[YourClass checkInternetConnectivityWithSuccessCompletion:^{
// your internet is working - add code here
}];

Which is the simplest way to check for Internet connection in iOS?

Take a look at the Reachability Example provided by Apple.

The problem your approach may have is that you could have a timeout and thus, the synchronized download of some data may block your app. As a result Apple may reject your app.

The Reachability Example can be used as follows:

Reachability *_reachability = [Reachability reachabilityForInternetConnection];
NetworkStatus remoteHostStatus = [_reachability currentReachabilityStatus];
if (remoteHostStatus == NotReachable) {
// not reachable
} else if (remoteHostStatus == ReachableViaWiFi) {
// reachable via Wifi
} else if (remoteHostStatus == ReachableViaWWAN) {
// reachable via WWAN
}

Check for internet connection with Swift

To solve the 4G issue mentioned in the comments I have used @AshleyMills reachability implementation as a reference and rewritten Reachability for Swift 3.1:

updated: Xcode 10.1 • Swift 4 or later


Reachability.swift file

import Foundation
import SystemConfiguration

class Reachability {
var hostname: String?
var isRunning = false
var isReachableOnWWAN: Bool
var reachability: SCNetworkReachability?
var reachabilityFlags = SCNetworkReachabilityFlags()
let reachabilitySerialQueue = DispatchQueue(label: "ReachabilityQueue")
init(hostname: String) throws {
guard let reachability = SCNetworkReachabilityCreateWithName(nil, hostname) else {
throw Network.Error.failedToCreateWith(hostname)
}
self.reachability = reachability
self.hostname = hostname
isReachableOnWWAN = true
try start()
}
init() throws {
var zeroAddress = sockaddr_in()
zeroAddress.sin_len = UInt8(MemoryLayout<sockaddr_in>.size)
zeroAddress.sin_family = sa_family_t(AF_INET)
guard let reachability = withUnsafePointer(to: &zeroAddress, {
$0.withMemoryRebound(to: sockaddr.self, capacity: 1) {
SCNetworkReachabilityCreateWithAddress(nil, $0)
}
}) else {
throw Network.Error.failedToInitializeWith(zeroAddress)
}
self.reachability = reachability
isReachableOnWWAN = true
try start()
}
var status: Network.Status {
return !isConnectedToNetwork ? .unreachable :
isReachableViaWiFi ? .wifi :
isRunningOnDevice ? .wwan : .unreachable
}
var isRunningOnDevice: Bool = {
#if targetEnvironment(simulator)
return false
#else
return true
#endif
}()
deinit { stop() }
}

extension Reachability {

func start() throws {
guard let reachability = reachability, !isRunning else { return }
var context = SCNetworkReachabilityContext(version: 0, info: nil, retain: nil, release: nil, copyDescription: nil)
context.info = Unmanaged<Reachability>.passUnretained(self).toOpaque()
guard SCNetworkReachabilitySetCallback(reachability, callout, &context) else { stop()
throw Network.Error.failedToSetCallout
}
guard SCNetworkReachabilitySetDispatchQueue(reachability, reachabilitySerialQueue) else { stop()
throw Network.Error.failedToSetDispatchQueue
}
reachabilitySerialQueue.async { self.flagsChanged() }
isRunning = true
}

func stop() {
defer { isRunning = false }
guard let reachability = reachability else { return }
SCNetworkReachabilitySetCallback(reachability, nil, nil)
SCNetworkReachabilitySetDispatchQueue(reachability, nil)
self.reachability = nil
}

var isConnectedToNetwork: Bool {
return isReachable &&
!isConnectionRequiredAndTransientConnection &&
!(isRunningOnDevice && isWWAN && !isReachableOnWWAN)
}

var isReachableViaWiFi: Bool {
return isReachable && isRunningOnDevice && !isWWAN
}

/// Flags that indicate the reachability of a network node name or address, including whether a connection is required, and whether some user intervention might be required when establishing a connection.
var flags: SCNetworkReachabilityFlags? {
guard let reachability = reachability else { return nil }
var flags = SCNetworkReachabilityFlags()
return withUnsafeMutablePointer(to: &flags) {
SCNetworkReachabilityGetFlags(reachability, UnsafeMutablePointer($0))
} ? flags : nil
}

/// compares the current flags with the previous flags and if changed posts a flagsChanged notification
func flagsChanged() {
guard let flags = flags, flags != reachabilityFlags else { return }
reachabilityFlags = flags
NotificationCenter.default.post(name: .flagsChanged, object: self)
}

/// The specified node name or address can be reached via a transient connection, such as PPP.
var transientConnection: Bool { return flags?.contains(.transientConnection) == true }

/// The specified node name or address can be reached using the current network configuration.
var isReachable: Bool { return flags?.contains(.reachable) == true }

/// The specified node name or address can be reached using the current network configuration, but a connection must first be established. If this flag is set, the kSCNetworkReachabilityFlagsConnectionOnTraffic flag, kSCNetworkReachabilityFlagsConnectionOnDemand flag, or kSCNetworkReachabilityFlagsIsWWAN flag is also typically set to indicate the type of connection required. If the user must manually make the connection, the kSCNetworkReachabilityFlagsInterventionRequired flag is also set.
var connectionRequired: Bool { return flags?.contains(.connectionRequired) == true }

/// The specified node name or address can be reached using the current network configuration, but a connection must first be established. Any traffic directed to the specified name or address will initiate the connection.
var connectionOnTraffic: Bool { return flags?.contains(.connectionOnTraffic) == true }

/// The specified node name or address can be reached using the current network configuration, but a connection must first be established.
var interventionRequired: Bool { return flags?.contains(.interventionRequired) == true }

/// The specified node name or address can be reached using the current network configuration, but a connection must first be established. The connection will be established "On Demand" by the CFSocketStream programming interface (see CFStream Socket Additions for information on this). Other functions will not establish the connection.
var connectionOnDemand: Bool { return flags?.contains(.connectionOnDemand) == true }

/// The specified node name or address is one that is associated with a network interface on the current system.
var isLocalAddress: Bool { return flags?.contains(.isLocalAddress) == true }

/// Network traffic to the specified node name or address will not go through a gateway, but is routed directly to one of the interfaces in the system.
var isDirect: Bool { return flags?.contains(.isDirect) == true }

/// The specified node name or address can be reached via a cellular connection, such as EDGE or GPRS.
var isWWAN: Bool { return flags?.contains(.isWWAN) == true }

/// The specified node name or address can be reached using the current network configuration, but a connection must first be established. If this flag is set
/// The specified node name or address can be reached via a transient connection, such as PPP.
var isConnectionRequiredAndTransientConnection: Bool {
return (flags?.intersection([.connectionRequired, .transientConnection]) == [.connectionRequired, .transientConnection]) == true
}
}

func callout(reachability: SCNetworkReachability, flags: SCNetworkReachabilityFlags, info: UnsafeMutableRawPointer?) {
guard let info = info else { return }
DispatchQueue.main.async {
Unmanaged<Reachability>
.fromOpaque(info)
.takeUnretainedValue()
.flagsChanged()
}
}

extension Notification.Name {
static let flagsChanged = Notification.Name("FlagsChanged")
}

struct Network {
static var reachability: Reachability!
enum Status: String {
case unreachable, wifi, wwan
}
enum Error: Swift.Error {
case failedToSetCallout
case failedToSetDispatchQueue
case failedToCreateWith(String)
case failedToInitializeWith(sockaddr_in)
}
}

Usage

Initialize it in your AppDelegate.swift didFinishLaunchingWithOptions method and handle any errors that might occur:

import UIKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
do {
try Network.reachability = Reachability(hostname: "www.google.com")
}
catch {
switch error as? Network.Error {
case let .failedToCreateWith(hostname)?:
print("Network error:\nFailed to create reachability object With host named:", hostname)
case let .failedToInitializeWith(address)?:
print("Network error:\nFailed to initialize reachability object With address:", address)
case .failedToSetCallout?:
print("Network error:\nFailed to set callout")
case .failedToSetDispatchQueue?:
print("Network error:\nFailed to set DispatchQueue")
case .none:
print(error)
}
}
return true
}
}

And a view controller sample:

import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default
.addObserver(self,
selector: #selector(statusManager),
name: .flagsChanged,
object: nil)
updateUserInterface()
}
func updateUserInterface() {
switch Network.reachability.status {
case .unreachable:
view.backgroundColor = .red
case .wwan:
view.backgroundColor = .yellow
case .wifi:
view.backgroundColor = .green
}
print("Reachability Summary")
print("Status:", Network.reachability.status)
print("HostName:", Network.reachability.hostname ?? "nil")
print("Reachable:", Network.reachability.isReachable)
print("Wifi:", Network.reachability.isReachableViaWiFi)
}
@objc func statusManager(_ notification: Notification) {
updateUserInterface()
}
}

Sample Project

How to detect internet connection when connected to wifi but no intenernet: iOS

In order to be sure that your device is really connected to internet, at least you have to try a ping to a up&running at anytime server (like stackoverflow.com o google.com).

Of course, as suggested by @jonrsharpe in question's comments, if this check is necessary in order to understand if app can reach the web server, then a ping or something like that to your web server is also necessary.

But a ping to a surely working web server (like google) will give you the answer it your device is connected to internet (so your modem can reach internet), that way if your web server is not responding you can accordingly show a warning alert in your app to inform user that currently your server is unreachable.

Going to code, you can try to check connection status with Reachability library like below

Reachability *reachability = [Reachability reachabilityWithHostName:@"stackoverflow.com"];
NetworkStatus networkStatus = [reachability currentReachabilityStatus];

and then check networkStatus variable: if 0 you don't have access to internet, otherwise YES, so

if(networkStatus==0) {
// no access to internet
} else {
// you have access to internet
}

IOS/Objective-C: Fastest way to check for Internet connection - 2017

Reachability is the correct way... even in 2017.

All the various Reachability classes are based on Apple's sample code.

It might seem complicated because it uses C APIs. But usage is simple:

- (BOOL)connected
{
Reachability *reach = [Reachability reachabilityForInternetConnection];

if ([reach isReachable]) {
NSLog(@"Device is connected to the internet");
return TRUE;
}
else {
NSLog(@"Device is not connected to the internet");
return FALSE;
}
}

If you will be using Apple's Reachability class instead of Tony Million's, replace [reach isReachable] with [reach currentReachabilityStatus] != NotReachable.

Don't worry that Apple might reject an app using it. If that happens to you, just rename the class from Reachability to MyReachability.



Related Topics



Leave a reply



Submit