Verifica la disponibilità della connessione Internet in Swift


107

C'è un modo per verificare se la connessione Internet è disponibile utilizzando Swift?

So che ci sono molte librerie di terze parti per farlo, ma sono tutte scritte in Objective-C. Sto cercando un'alternativa Swift.


5
Uno degli enormi vantaggi di Swift è che si integra bene con Objective-C (e le librerie di questo tipo).
user2864740

Infatti. Quali problemi stai riscontrando utilizzando una delle librerie esistenti? È piuttosto semplice utilizzare una libreria Objective C di Swift e sarà estremamente difficile per te scrivere qualsiasi tipo di app in Swift se non puoi farlo.
Matt Gibson

1
@ MattGibson quasi tutto ciò che puoi fare in ObjC può essere fatto in Swift con relativa facilità. Certo, in questo caso ci sarebbero alcune righe in più ma ancora tutt'altro che "estremamente difficili"
Byron Coetsee

@ByronCoetsee Ho incluso l'uso di librerie come AppKit, ecc. - Il punto è che dovrai sapere come interagire con le librerie Objective C per scrivere qualcosa di utile in Swift.
Matt Gibson

Vedere alamofire risposta - stackoverflow.com/a/46562290/7576100
Jack

Risposte:


228

Come accennato nei commenti, sebbene sia possibile utilizzare le librerie Objective-C in Swift, volevo una soluzione Swift più pura. La classe Apple Reachability esistente e altre librerie di terze parti sembravano essere troppo complicate per me da tradurre in Swift. Ho cercato ancora su Google e mi sono imbattuto in questo articolo che mostra un metodo semplice per verificare la disponibilità della rete. Ho deciso di tradurre questo in Swift. Ho incontrato molti ostacoli, ma grazie a Martin R di StackOverflow, sono riuscito a risolverli e finalmente a ottenere una soluzione praticabile in Swift. Ecco il codice.

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
    }

}

Per 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)
    }
}

Funziona sia per le connessioni 3G che WiFi. L'ho anche caricato sul mio GitHub con un esempio funzionante.


7
Grazie per la rapida risposta (nessun gioco di parole). MIT o Apache sarebbero l'ideale, grazie!
Andrew Ebling

4
Fatto. L'ho cambiato in MIT.
Isuru

11
Ho riscontrato un altro problema, se il 3G è attivato ma non ho più capacità di dati, isConnectedToNetworkrestituisce true, ma non riesco a chiamare il mio servizio web
János

11
Come ha detto @Isuru, questo è basato su stackoverflow.com/a/25623647/1187415 , che è stato ora aggiornato per Swift 2.
Martin R

2
@ János: ora è possibile impostare una richiamata di notifica con Swift 2, vedere la risposta aggiornata stackoverflow.com/a/27142665/1187415 .
Martin R

16

Ti do un modo migliore ...

Devi creare una classe con questo codice

 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
  }
}

E poi puoi controllare la connessione Internet ovunque nel tuo progetto usando questo codice:

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

Molto facile!

* In questo modo si basa sulla risposta di Vikram Pote!


15
Si prega di essere consapevoli del fatto che si dovrebbe non utilizzare questo metodo rispetto a quello utilizzato in precedenza. Nelle applicazioni che richiedono una connettività costante, un controllo della risposta come questo metodo comporterà il blocco dell'app in situazioni in cui la connettività Internet è scarsa (ad esempio su Edge / GPRS). Per favore non utilizzare questa soluzione !!
Imran Ahmed

7
Modo sbagliato 1) Serve un colpo extra al server ogni volta 2) Anche google.com può essere inattivo
Vijay Singh Rana

2
1. Sì, in questo modo è necessario ogni volta un tocco extra al server, ma garantisce al 100% che Internet sia disponibile ... ci sono momenti in cui il dispositivo è connesso a una rete wifi ma non fornisce l'accesso a Internet! In questa situazione, questo modo determina la mancanza di accesso a Internet ... altri modi - no! 2. Puoi utilizzare il tuo server al posto di google.com ... Questo era originariamente inteso ...
Dmitry

1
pessima soluzione, connessione killer.
gokhanakkurt

2
gokhanakkurt, per favore, suggerisci un'altra soluzione che assicuri che Internet funzioni al 100%
Dmitry

15

Per Swift 3.1 (iOS 10.1)

Se vuoi fare la distinzione tra il tipo di rete (cioè WiFi o WWAN):

Puoi usare:

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
    }
}

Ecco l'intera classe di raggiungibilità che distingue tra i tipi di rete:

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
        }
    }
}

funziona bene dal 3 dicembre 2016, iOS 10 e swift 3.1, grazie!
joey

Ciao, se vogliamo differenziare la connessione Wifi / 3G / Dati mobili / 4G per questo come possiamo identificare.

6

Poiché sendSynchronousRequest è deprecato, l'ho provato ma è stato chiamato "return Status" prima che la risposta fosse terminata.

Questa risposta funziona bene, controlla la connessione a Internet con Swift

Ecco cosa ho provato comunque:

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
    }
}

Mi è piaciuta e ho usato la tua soluzione. Ma ho aggiunto un combinato con questa risposta: stackoverflow.com/a/34591379 aka. ho aggiunto un semaforo .. Quindi aspetto che l'attività finisca.
Bjqn

6

SWIFT 3: verifica la connessione Wi - Fi e Internet :

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)
    }
}

USO:

if Reachability.isConnectedToNetwork() == true {
    print("Connected to the internet")
    //  Do something
} else {
    print("No internet connection")
    //  Do something
}

2
public func isConnectedToNetwork() {...}dovrebbe essere cambiato in class func isConnectedToNetwork{...}per il tuo caso di utilizzo.
keverly

4

Puoi anche usare la risposta sottostante.

    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
        }
    })
   }

Grazie! Ho ricevuto una correzione automatica dalla risposta come NSHTTPURLResponse? alla risposta come! NSHTTPURLResponse? in Swift 1.2.
Francis Jervis

1

SWIFT 3: controlla la connessione 3G e Wi-Fi

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()
}

Questo non è un modo preferito. E se in futuro il collegamento Web fornito smette di rispondere o non funziona. Suggerirei di utilizzare il framework Apple SystemConfiguration per questo. Vedi la risposta sopra.
Abdul Yasin

1

Per 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
}

1

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)
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.