deadcoder0904
deadcoder0904

Reputation: 8693

How to know whether actual internet is available or not in Swift?

I want to get notified when my WiFi Router color changes from Green to Red

I am making an app which will tell you whether you are online or offline from menu bar in Swift which is open source & can be found at https://github.com/deadcoder0904/net-alert

I want to know if its possible to get notified when WiFi color changes in Swift.

I can't constantly ping my server to know that the color changed as this would be wasting internet resources.

So is it possible to know this in Swift?

Upvotes: 1

Views: 1845

Answers (2)

nayem
nayem

Reputation: 7605

First of all, I'm going to answer this from iOS perspective. But your GitHub demo is for macOS. I think the basics are the same.

I'll go to solve this in protocol oriented approach.


Update:

After quite a lot of searching I've come across the magnificent implementation of Connectivity wrapper. There is even a descriptive blogpost Solving the Captive Portal Problem on iOS if you want to know more about it. This implementation is capable of dealing with actual internet available / not-available states.

Note: Don't like to read further? Here is the working version that I'm going to illustrate briefly. Navigation bar will reflect with Green & Red color for different connection status.

Define a protocol:

This protocol will help any interested object to be notified when any change in connectivity occurs.

protocol ConnectivityNotifiable {
    var connectivity: Connectivity { get }
    func startNotifyingConnectivityChangeStatus()
    func stopNotifyingConnectivityChangeStatus()
    func connectivityChanged(toStatus: ConnectivityStatus)
}

// Provide some default implementation through protocol extension
extension ConnectivityNotifiable {
    func startNotifyingConnectivityChangeStatus() {
        connectivity.isPollingEnabled = true
        connectivity.startNotifier()
        connectivity.whenConnected = { connectivity in
            self.connectivityChanged(toStatus: connectivity.status)
        }
        connectivity.whenDisconnected = { connectivity in
            self.connectivityChanged(toStatus: connectivity.status)
        }
    }
    func stopNotifyingConnectivityChangeStatus() {
        connectivity.stopNotifier()
    }
}

Conform to the protocol:

Conforming to the ConnectivityNotifiable protocol will add the functionality to any interested object to be notified when Connectivity status changes. Something like monitoring.

class ViewController: UIViewController, ConnectivityNotifiable {

    // ConnectivityNotifiable protocol requirement
    let connectivity = Connectivity()

    override func viewDidLoad() {
        super.viewDidLoad()

        // Invoke the default implementation of the ConnectivityNotifiable protocol
        // requirement to be able to be notified
        startNotifyingConnectivityChangeStatus()

        // Reminder:
        // Don't forget to invoke stopNotifyingConnectivityChangeStatus() when
        // you are done or when the lifecycle of your controller ends
    }

    // ConnectivityNotifiable protocol requirement
    func connectivityChanged(toStatus: ConnectivityStatus) {
        // Everytime any change happens in the network connectivity 
        // this method will be invoked with appropriate connection status
        switch toStatus {

        case .connected, 
             .connectedViaWiFi, 
             .connectedViaCellular:
            // Connected/Internet available. Update any UI component

        case .notConnected, 
             .connectedViaWiFiWithoutInternet, 
             .connectedViaCellularWithoutInternet:
            // Disconnected/Internet not available. Update any UI component
        }
    }
}


Old Answer

Note: If you are using the latest release of the Reachability, you won't need the NotificationCenter based solution to get reachability change notification. It works completely fine with closure based approach.


Don't like to know how to achieve this? Here is a working version made for iOS platform. Clone the repo and check yourself. Navigation bar will reflect with Green, Orange & Red color for different connection status.

Define a protocol:

This protocol will help any interested object to be notified when any change in reachability occurs.

protocol Reachable {
    var reachability: Reachability { get }
    func startMonitoringReachabilityChangeStatus()
    func reachabilityChanged(to: Reachability.Connection)
}

extension Reachable {
    func startMonitoringReachabilityChangeStatus() {
        do {
            try reachability.startNotifier()
        } catch {
            print(error.localizedDescription)
        }
        reachability.whenReachable = { reachability in
            self.reachabilityChanged(to: reachability.connection)
        }
        reachability.whenUnreachable = { reachability in
            self.reachabilityChanged(to: reachability.connection)
        }
    }
}

Conform to the protocol:

Conforming to the Reachable protocol will add the functionality to any interested object to be notified when reachability status changes. Something like monitoring.

class ViewController: UIViewController, Reachable {

    // Reachable protocol requirement
    let reachability: Reachability = Reachability()!

    override func viewDidLoad() {
        super.viewDidLoad()

        // initial reachability checkup
        reachabilityChanged(to: reachability.connection)

        // Invoke the default implementation of the Reachable protocol requirement 
        // to be able to be notified
        startMonitoringReachabilityChangeStatus()
    }

    // Reachable protocol requirement
    func reachabilityChanged(to: Reachability.Connection) {
        // Everytime any change happens in the network connectivity 
        // this method will be invoked with appropriate connection status
        switch to {
        case .wifi:
            DispatchQueue.main.async {
                // Update any UI component
            }
        case .cellular:
            DispatchQueue.main.async {
                // Update any UI component
            }
        case .none:
            DispatchQueue.main.async {
                // Update any UI component
            }
        }
    }
}

Upvotes: 8

daris mathew
daris mathew

Reputation: 429

I went through the code and the way you did doesn't notify you when the internet connection is interrupted, it just checks at the runtime whether there is connection or not. To achieve what you want we need to add Notifications.

First, declare the reachability var

 private var reachability:Reachability!;

THen add the following code in your didFinishLaunchingWithOptions method in the appdelegate

 self.reachability = Reachability.init()
         NotificationCenter.default.addObserver(self, selector: #selector(checkForReachability(notification:)), name: .reachabilityChanged, object: reachability)
        do{
            try reachability.startNotifier()
        }catch{
            print("could not start reachability notifier")
        }

What we do is initialise the reachability variable and create a notification observer to detect when the connection state changes with help of Notifier.

And finally the selector method is

@objc func checkForReachability(notification:NSNotification)
    {
        let reachability = notification.object as! Reachability
        switch reachability.connection {
        case .wifi:
            print("Reachable via WiFi")
        case .cellular:
            print("Reachable via Cellular")
        case .none:
            print("Network not reachable")
        }
    }

That's it, from now on when the internet connection is interrupted we get notified and in the above method you can change the colour of the menu bar icon.

Upvotes: 0

Related Questions