Check for internet connection availability in Swift
Asked Answered
C

11

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.

Copyboy answered 20/8, 2014 at 7:4 Comment(6)
One of Swift's huge benefits is that it integrates well with Objective-C (and libraries of such).Halide
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.Obsequies
@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"Weightless
@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.Obsequies
See alamofire answer - https://mcmap.net/q/48297/-check-for-internet-connection-with-swiftTroxler
https://mcmap.net/q/46288/-how-to-check-internet-connection-in-alamofireExplicable
C
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.

Copyboy answered 10/9, 2014 at 20:22 Comment(20)
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.Subzero
Oh sure. What would you suggest to be the suitable one?Copyboy
Thanks for the swift response (no pun intended). MIT or Apache would be ideal - thanks!Subzero
Done. Changed it to MIT.Copyboy
Hello Isuru, I found a much simplier looking code, but maybe not as good as yours: What do you think about that: ios8programminginswift.wordpress.com/2014/08/17/…Photoluminescence
@Photoluminescence 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.Copyboy
@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!Photoluminescence
is a way to get notification if user changes network settings, i.e. put device to airplane mode? I need to reload tableViewJoelynn
@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 I asked regarding this. Sorry.Copyboy
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 serviceJoelynn
As @Copyboy said, this is based on https://mcmap.net/q/48801/-how-to-use-scnetworkreachability-in-swift, which has now been updated for Swift 2.Horsefly
@János: Setting a notification callback is now possible with Swift 2, see updated answer https://mcmap.net/q/49177/-working-with-c-apis-from-swift.Horsefly
swift 2 update :#30740500Undertrick
The swift2 update doesn't cover the full code, I'm still receiving errors on the code in Swift2Whereunto
@János have you found a solution?Possibly
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 CodingZook
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.Fowliang
This code is based on https://mcmap.net/q/48801/-how-to-use-scnetworkreachability-in-swift (essentially a copy of revision 6), which has now been updated for the latest Swift 3 from Xcode 8 beta 6.Horsefly
@Copyboy This does NOT work when you are connected to 4G network. It returns falseLivvie
is there a way of creating an observer from this?Thunderbolt
C
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
        }
    }
}
Chimborazo answered 11/11, 2016 at 13:13 Comment(2)
working well as of Dec 3, 2016, iOS 10 and swift 3.1, thanks!Linkous
Hello, if we want to differentiate Wifi/3G/Mobile-Data/4G connection for that how we can identify.Yodle
R
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!

Readymade answered 14/3, 2015 at 15:31 Comment(7)
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!!Leuko
Bad way 1) Need extra hit to server evry time 2) google.com can also be downHarriet
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 ...Readymade
poor solution, connection killer.Doggo
gokhanakkurt, please, suggest another solution that ensures that the Internet works at 100%Readymade
call an url to check if there is a connection is bad practice.Mansuetude
You assume 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.Kerman
D
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
}
Darbee answered 22/12, 2016 at 14:32 Comment(1)
public func isConnectedToNetwork() {...} should be changed to class func isConnectedToNetwork{...} for your usage case.Grof
A
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
    }
}
Aron answered 19/10, 2015 at 8:56 Comment(1)
I liked and used yours solution. But i added a combined it with this answer: stackoverflow.com/a/34591379 aka. i added a semaphore.. So i wait for the the task to finish.Chiffchaff
L
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
        }
    })
   }
Laodicea answered 12/3, 2015 at 11:46 Comment(1)
Thanks! I got an auto-correct from response as NSHTTPURLResponse? to response as! NSHTTPURLResponse? in Swift 1.2.Ampliate
E
3

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")") 
Exarch answered 3/9, 2022 at 18:56 Comment(0)
J
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)
}
Jeffcott answered 17/3, 2018 at 7:21 Comment(0)
N
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
}
Nonesuch answered 17/11, 2019 at 18:52 Comment(1)
Seems like this won't work as you didn't do monitor.start(queue: someQueue)Agha
I
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)
    }

}
Igniter answered 4/10, 2020 at 8:59 Comment(0)
A
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()
}
Arv answered 21/12, 2016 at 20:40 Comment(1)
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.Fleam

© 2022 - 2024 — McMap. All rights reserved.