109

Is there a way to check if the internet connection is available using Swift?

I know there are many third party libraries to do this but they are all written in Objective-C. I'm looking for a Swift alternative.

Isuru
  • 30,617
  • 60
  • 187
  • 303
  • 5
    One of Swift's huge benefits is that it integrates well with Objective-C (and libraries of such). – user2864740 Aug 20 '14 at 07:06
  • Indeed. What problems are you having using one of the existing libraries? It's pretty simple to use an Objective C library from Swift, and it's going to prove extremely difficult for you to write any kind of app in Swift if you can't do it. – Matt Gibson Aug 20 '14 at 08:36
  • 1
    @MattGibson almost everything you can do in ObjC can be done in Swift with relative ease. Granted, in this case there would be a few extra lines but still far from "extremely difficult" – Byron Coetsee Dec 13 '14 at 17:16
  • @ByronCoetsee I was including using libraries like AppKit, etc.—my point is that you'll need to know how to interact with Objective C libraries in order to write anything useful in Swift. – Matt Gibson Dec 13 '14 at 17:24
  • See alamofire answer - https://stackoverflow.com/a/46562290/7576100 – Jack Oct 04 '17 at 11:04
  • https://stackoverflow.com/a/42710600/6898523 – MAhipal Singh Jul 20 '18 at 07:13

11 Answers11

231

As mentioned in the comments, although its possible to use Objective-C libraries in Swift, I wanted a more pure Swift solution. The existing Apple Reachability class and other third party libraries seemed to be too complicated for me to translate to Swift. I Googled some more and I came across this article which shows a simple method to check for network availability. I set out to translate this to Swift. I hit many snags but thanks to Martin R from StackOverflow, I managed to resolve them and finally get a workable solution in Swift. Here is the code.

import Foundation
import SystemConfiguration

public class Reachability {

    class func isConnectedToNetwork() -> Bool {

        var zeroAddress = sockaddr_in(sin_len: 0, sin_family: 0, sin_port: 0, sin_addr: in_addr(s_addr: 0), sin_zero: (0, 0, 0, 0, 0, 0, 0, 0))
        zeroAddress.sin_len = UInt8(sizeofValue(zeroAddress))
        zeroAddress.sin_family = sa_family_t(AF_INET)

        let defaultRouteReachability = withUnsafePointer(&zeroAddress) {
            SCNetworkReachabilityCreateWithAddress(nil, UnsafePointer($0)).takeRetainedValue()
        }

        var flags: SCNetworkReachabilityFlags = 0
        if SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags) == 0 {
            return false
        }

        let isReachable = (flags & UInt32(kSCNetworkFlagsReachable)) != 0
        let needsConnection = (flags & UInt32(kSCNetworkFlagsConnectionRequired)) != 0

        return isReachable && !needsConnection
    }

}

For Swift > 3.0

public class Reachability {
    public func isConnectedToNetwork() -> Bool {
        var zeroAddress = sockaddr_in()
        zeroAddress.sin_len = UInt8(MemoryLayout<sockaddr_in>.size)
        zeroAddress.sin_family = sa_family_t(AF_INET)

        guard let defaultRouteReachability = withUnsafePointer(to: &zeroAddress, {
            $0.withMemoryRebound(to: sockaddr.self, capacity: 1) {
                SCNetworkReachabilityCreateWithAddress(nil, $0)
            }
        }) else {
            return false
        }

        var flags: SCNetworkReachabilityFlags = []
        if !SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags) {
            return false
        }
        if flags.isEmpty {
            return false
        }

        let isReachable = flags.contains(.reachable)
        let needsConnection = flags.contains(.connectionRequired)

        return (isReachable && !needsConnection)
    }
}

This works for both 3G and WiFi connections. I've also uploaded it to my GitHub with a working example.

aaannjjaa
  • 338
  • 3
  • 6
Isuru
  • 30,617
  • 60
  • 187
  • 303
  • Please can you consider releasing this code under a less restrictive licence? Especially seeing as the original code which it is based upon seems to have been released without any licence. – Andrew Ebling Nov 13 '14 at 14:53
  • Oh sure. What would you suggest to be the suitable one? – Isuru Nov 13 '14 at 15:05
  • 7
    Thanks for the swift response (no pun intended). MIT or Apache would be ideal - thanks! – Andrew Ebling Nov 13 '14 at 15:08
  • 4
    Done. Changed it to MIT. – Isuru Nov 13 '14 at 15:36
  • Hello Isuru, I found a much simplier looking code, but maybe not as good as yours: What do you think about that: https://ios8programminginswift.wordpress.com/2014/08/17/how-to-check-for-an-active-internet-connection/ – LukeSideWalker Jan 18 '15 at 01:31
  • @LukeSideWalker I've seen that post too. I even tried it myself but the code simply didn't work. I got a few compiler errors saying there is no type called `Reachability` which is understandable because `SystemConfiguration` framework doesn't support this functionality out of the box as far as I know. Did it work for you? I left a comment in that post as well. Guess the user either didn't approve it or removed it. – Isuru Jan 18 '15 at 14:45
  • @Isuru: Thank you very much for your answer and sorry, that I consumed your time with that link to a code, that of course does not work. It is just, I was so impressed by the complexity of your code, since I don't understand really what is happening in your class Reachability, but I can confirm, it works perfectly. But when I was looking for an alternative code, that is less complex and maybe understandable for me, I would have taken that. But as already said, that code is not less complex, it is simple not working ! Sorry again for you time and thanks for your great code! – LukeSideWalker Jan 18 '15 at 21:13
  • is a way to **get notification** if user changes network settings, i.e. put device to airplane mode? I need to reload tableView – János Mar 28 '15 at 12:13
  • @János Currently this is impossible to achieve in Swift the way it's done in Objective-C. `SCNetworkReachabilitySetCallback` expects a pointer to a C function as second parameter, and there is currently no method to pass a Swift function or closure.. Here's the [question](http://stackoverflow.com/q/27142263/1077789) I asked regarding this. Sorry. – Isuru Mar 28 '15 at 16:16
  • 13
    I found an other issue, if **3G is turned on** but I have no more data capacity then `isConnectedToNetwork` returns true, **but I can not call my web service** – János Mar 28 '15 at 20:56
  • 11
    As @Isuru said, this is based on http://stackoverflow.com/a/25623647/1187415, which has now been updated for Swift 2. – Martin R Jun 10 '15 at 01:52
  • 2
    @János: Setting a notification callback is now possible with Swift 2, see updated answer http://stackoverflow.com/a/27142665/1187415. – Martin R Jun 10 '15 at 02:12
  • 1
    swift 2 update :http://stackoverflow.com/questions/30740000/withunsafepointer-in-swift-2 – Paraneetharan Saravanaperumal Jun 11 '15 at 06:37
  • 1
    The swift2 update doesn't cover the full code, I'm still receiving errors on the code in Swift2 – Wraithseeker Sep 28 '15 at 10:22
  • @János have you found a solution? – suisied Oct 10 '15 at 10:36
  • I added an answer at the bottom you should look at and update you answer. The c code in your logic up there is broken in swift 2.0. Use the swift structs instead of the objective c enums and you should be good. Happy Coding – A'sa Dickens Oct 16 '15 at 14:40
  • Another issue if you are connected to a public wifi but it takes you to a splash page or require you to 'login' before you can proceed. In this case you are connected but you cannot access the web.I combined the above with a ping to Google. – zevij Jan 17 '16 at 11:50
  • This code is based on http://stackoverflow.com/a/25623647/1187415 (essentially a copy of revision 6), which has now been updated for the latest Swift 3 from Xcode 8 beta 6. – Martin R Aug 20 '16 at 11:35
  • 2
    @Isuru This does NOT work when you are connected to 4G network. It returns false – ChaturaM Sep 15 '16 at 05:25
  • is there a way of creating an observer from this? – SwiftER Feb 25 '17 at 04:08
15

For Swift 3.1 (iOS 10.1)

If you want to make the distinction between the network-type (i.e. WiFi or WWAN):

You can use:

func checkWiFi() -> Bool {

    let networkStatus = Reachability().connectionStatus()
    switch networkStatus {
    case .Unknown, .Offline:
        return false
    case .Online(.WWAN):
        print("Connected via WWAN")
        return true
    case .Online(.WiFi):
        print("Connected via WiFi")
        return true
    }
}

Here is the entire Reachability-Class that distinguished between network-types:

import Foundation
import SystemConfiguration

import UIKit
import SystemConfiguration.CaptiveNetwork

public let ReachabilityStatusChangedNotification = "ReachabilityStatusChangedNotification"

public enum ReachabilityType: CustomStringConvertible {
    case WWAN
    case WiFi

    public var description: String {
        switch self {
        case .WWAN: return "WWAN"
        case .WiFi: return "WiFi"
        }
    }
}

public enum ReachabilityStatus: CustomStringConvertible  {
    case Offline
    case Online(ReachabilityType)
    case Unknown

    public var description: String {
        switch self {
        case .Offline: return "Offline"
        case .Online(let type): return "Online (\(type))"
        case .Unknown: return "Unknown"
        }
    }
}

public class Reachability {

    func connectionStatus() -> ReachabilityStatus {
        var zeroAddress = sockaddr_in()
        zeroAddress.sin_len = UInt8(MemoryLayout.size(ofValue: zeroAddress))
        zeroAddress.sin_family = sa_family_t(AF_INET)

        guard let defaultRouteReachability = (withUnsafePointer(to: &zeroAddress) {
            $0.withMemoryRebound(to: sockaddr.self, capacity: 1) { zeroSockAddress in
                SCNetworkReachabilityCreateWithAddress(nil, zeroSockAddress)
            }
        }) else {
           return .Unknown
        }

        var flags : SCNetworkReachabilityFlags = []
        if !SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags) {
            return .Unknown
        }

        return ReachabilityStatus(reachabilityFlags: flags)
    }

    func monitorReachabilityChanges() {
        let host = "google.com"
        var context = SCNetworkReachabilityContext(version: 0, info: nil, retain: nil, release: nil, copyDescription: nil)
        let reachability = SCNetworkReachabilityCreateWithName(nil, host)!

        SCNetworkReachabilitySetCallback(reachability, { (_, flags, _) in
            let status = ReachabilityStatus(reachabilityFlags: flags)

            NotificationCenter.default.post(name: NSNotification.Name(rawValue: ReachabilityStatusChangedNotification), object: nil, userInfo: ["Status": status.description])}, &context)

        SCNetworkReachabilityScheduleWithRunLoop(reachability, CFRunLoopGetMain(), CFRunLoopMode.commonModes.rawValue)
    }
}

extension ReachabilityStatus {

    public init(reachabilityFlags flags: SCNetworkReachabilityFlags) {
        let connectionRequired = flags.contains(.connectionRequired)
        let isReachable = flags.contains(.reachable)
        let isWWAN = flags.contains(.isWWAN)

        if !connectionRequired && isReachable {
            if isWWAN {
                self = .Online(.WWAN)
            } else {
                self = .Online(.WiFi)
            }
        } else {
            self =  .Offline
        }
    }
}
iKK
  • 6,394
  • 10
  • 58
  • 131
14

I give you better way...

You must create a class with this code

 import Foundation
 public class Reachability {

class func isConnectedToNetwork()->Bool{

    var Status:Bool = false
    let url = NSURL(string: "http://google.com/")
    let request = NSMutableURLRequest(URL: url!)
    request.HTTPMethod = "HEAD"
    request.cachePolicy = NSURLRequestCachePolicy.ReloadIgnoringLocalAndRemoteCacheData
    request.timeoutInterval = 10.0

    var response: NSURLResponse?

    var data = NSURLConnection.sendSynchronousRequest(request, returningResponse: &response, error: nil) as NSData?

    if let httpResponse = response as? NSHTTPURLResponse {
        if httpResponse.statusCode == 200 {
            Status = true
        }
    }

    return Status
  }
}

And then you can check internet connection anywhere in your project using this code:

if Reachability.isConnectedToNetwork() == true {
     println("Internet connection OK")
} else {
     println("Internet connection FAILED")
}

Very easy!

*This way is based on Vikram Pote answer!

Dmitry
  • 2,963
  • 2
  • 21
  • 39
  • 20
    Please be aware that you should **not** use this method over the one used above. In applications which require constant connectivity, a response check like this method will result in the app hanging in situations where your internet connectivity is poor (i.e. on Edge/GPRS). Please don't use this solution!! – Imran Ahmed Jul 22 '15 at 23:16
  • 8
    Bad way 1) Need extra hit to server evry time 2) http://google.com/ can also be down – Vijay Singh Rana Sep 30 '15 at 13:12
  • 2
    1. Yes, this way need extra hit to server every time, but it gives a 100% guarantee that the Internet is available... there are times when the device is connected to a wifi network but does not provide internet access! In this situation, this way determines the lack of access to the Internet ... other ways - no! 2. You can use your own server instead google.com ... This was originally meant ... – Dmitry Oct 18 '15 at 11:03
  • 1
    poor solution, connection killer. – gokhanakkurt Nov 26 '15 at 15:10
  • 3
    gokhanakkurt, please, suggest another solution that ensures that the Internet works at 100% – Dmitry Nov 26 '15 at 16:12
  • call an url to check if there is a connection is bad practice. – Cocorico Feb 23 '16 at 13:43
  • You assume http://google.com web-server is some kind of nature force, that is always available? what kind of technical assumption is this? Also this harasses a specific server which is bad practice. Last, this test will take longer than other methods, because it depends on the response-times of Google servers, not the actual network. It is usually preferable to go a far as your ISP - and no more - to verify "internet" availability. For "Network" availability, even closer - no farther than the nearest router. – Motti Shneor Nov 20 '16 at 07:50
7

SWIFT 3: Checks for wifi and internet connection:

import Foundation
import SystemConfiguration

public class Reachability {
    public func isConnectedToNetwork() -> Bool {
        var zeroAddress = sockaddr_in()
        zeroAddress.sin_len = UInt8(MemoryLayout<sockaddr_in>.size)
        zeroAddress.sin_family = sa_family_t(AF_INET)

        guard let defaultRouteReachability = withUnsafePointer(to: &zeroAddress, {
            $0.withMemoryRebound(to: sockaddr.self, capacity: 1) {
                SCNetworkReachabilityCreateWithAddress(nil, $0)
            }
        }) else {
            return false
        }

        var flags: SCNetworkReachabilityFlags = []
        if !SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags) {
            return false
        }

        let isReachable = flags.contains(.reachable)
        let needsConnection = flags.contains(.connectionRequired)

        return (isReachable && !needsConnection)
    }
}

USAGE:

if Reachability.isConnectedToNetwork() == true {
    print("Connected to the internet")
    //  Do something
} else {
    print("No internet connection")
    //  Do something
}
Gilad Brunfman
  • 3,452
  • 1
  • 29
  • 29
  • 2
    `public func isConnectedToNetwork() {...}` should be changed to `class func isConnectedToNetwork{...}` for your usage case. – keverly Feb 15 '17 at 00:43
5

Since sendSynchronousRequest is deprecated, I tried this but 'return Status' was called before the response had finished.

This answer works well though, Check for internet connection with Swift

Here's what I tried anyway:

import Foundation

public class Reachability {

    class func isConnectedToNetwork()->Bool{

        var Status:Bool = false
        let url = NSURL(string: "http://google.com/")
        let request = NSMutableURLRequest(URL: url!)
        request.HTTPMethod = "HEAD"
        request.cachePolicy = NSURLRequestCachePolicy.ReloadIgnoringLocalAndRemoteCacheData
        request.timeoutInterval = 10.0
        let session = NSURLSession.sharedSession()

        session.dataTaskWithRequest(request, completionHandler: {(data, response, error) in
            print("data \(data)")
            print("response \(response)")
            print("error \(error)")

            if let httpResponse = response as? NSHTTPURLResponse {
                print("httpResponse.statusCode \(httpResponse.statusCode)")
                if httpResponse.statusCode == 200 {
                    Status = true
                }
            }

        }).resume()


        return Status
    }
}
Community
  • 1
  • 1
Sarah
  • 75
  • 1
  • 2
  • I liked and used yours solution. But i added a combined it with this answer: http://stackoverflow.com/a/34591379 aka. i added a semaphore.. So i wait for the the task to finish. – Bjqn Jul 15 '16 at 13:59
4

You can also use below answer.

    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" mean Google
        }
        else
        {
            // No "Internet" no Google
        }
    })
   }
Vikram Pote
  • 5,433
  • 4
  • 33
  • 37
2

Swift 4

if isInternetAvailable() {
    print("if called Internet Connectivity success \(isInternetAvailable())");
} else {
    print("else called Internet Connectivity success \(isInternetAvailable())");
}

func isInternetAvailable() -> Bool {
    var zeroAddress = sockaddr_in()
    zeroAddress.sin_len = UInt8(MemoryLayout.size(ofValue: zeroAddress))
    zeroAddress.sin_family = sa_family_t(AF_INET)
    let defaultRouteReachability = withUnsafePointer(to: &zeroAddress) {
        $0.withMemoryRebound(to: sockaddr.self, capacity: 1) {zeroSockAddress in
            SCNetworkReachabilityCreateWithAddress(nil, zeroSockAddress)
     }
    }

   var flags = SCNetworkReachabilityFlags()

   if !SCNetworkReachabilityGetFlags(defaultRouteReachability!, &flags) {
      return false
   }
   let isReachable = flags.contains(.reachable)
   let needsConnection = flags.contains(.connectionRequired)
   //   print(isReachable && !needsConnection)
   return (isReachable && !needsConnection)
}
Luckabo
  • 74
  • 5
Keshav Gera
  • 10,807
  • 1
  • 75
  • 53
2

For Swift 5:

import Network
let monitor = NWPathMonitor()

func checkInterwebs() -> Bool {
    var status = false
    monitor.pathUpdateHandler = { path in
        if path.status == .satisfied {
            status = true  // online
        }
    }
    return status
}
RandallShanePhD
  • 5,406
  • 2
  • 20
  • 30
2

If you use Alamofire in your project you can Use this sample func:

import Alamofire

class Network {

    func isConnected(_ complition: @escaping(Bool) -> Void) {
        let retVal = NetworkReachabilityManager()!.isReachable
        complition(retVal)
    }

}
mohsen
  • 4,698
  • 1
  • 33
  • 54
2

If you just want to know if it's connected or not and you're using SwiftUI:

Service:

import Foundation
import Network

class ConnectionService: ObservableObject {
    @Published var connected: Bool = false
    
    private var monitor: NWPathMonitor
    
    init() {
        monitor = NWPathMonitor()

        monitor.pathUpdateHandler = { [weak self] path in
            switch path.status {
            case .satisfied:
                self?.connected = true
            case .unsatisfied, .requiresConnection:
                self?.connected = false
            @unknown default:
                self?.connected = false
            }
        }

        monitor.start(queue: DispatchQueue.main)
    }
}

Usage:

// step 1: add in your App struct
@StateObject var internet = ConnectionService() 

// step 2: add this modifier to your top level view
.environmentObject(internet) 

// step 3: add this in any child view
@EnvironmentObject var internet: ConnectionService 

// step 4: example usage in that child view
Text("internet: \(internet.connected ? "true" : "false")") 
Akash Kundu
  • 1,278
  • 13
  • 21
0

SWIFT 3: Check 3G & Wi-Fi connection

DispatchQueue.main.async {
        let url = URL(string: "https://www.google.com")!
        let request = URLRequest(url: url)

        let task = URLSession.shared.dataTask(with: request) {data, response, error in

            if error != nil {
                // do something here...
                print("Internet Connection not Available!")
            }
            else if let httpResponse = response as? HTTPURLResponse {
                if httpResponse.statusCode == 200 {
                    // do something here...
                    print("Internet Connection OK")
                }
                print("statusCode: \(httpResponse.statusCode)")
            }

        }
        task.resume()
}
Włodzimierz Woźniak
  • 3,106
  • 1
  • 26
  • 23
  • This is not a preferred way. What if at some point of future the provided web link stops to respond or is down. I would recommend to use Apple SystemConfiguration framework for this. See the above answer. – Abdul Yasin Nov 15 '17 at 07:10