Vérifiez la disponibilité de la connexion Internet dans Swift

107

Existe-t-il un moyen de vérifier si la connexion Internet est disponible avec Swift?

Je sais qu'il existe de nombreuses bibliothèques tierces pour ce faire, mais elles sont toutes écrites en Objective-C. Je recherche une alternative Swift.

Isuru
la source
5
L'un des énormes avantages de Swift est qu'il s'intègre bien avec Objective-C (et les bibliothèques de ce type).
user2864740
En effet. Quels problèmes rencontrez-vous en utilisant l'une des bibliothèques existantes? Il est assez simple d'utiliser une bibliothèque Objective C de Swift, et il vous sera extrêmement difficile d'écrire n'importe quel type d'application dans Swift si vous ne pouvez pas le faire.
Matt Gibson
1
@MattGibson presque tout ce que vous pouvez faire dans ObjC peut être fait dans Swift avec une relative facilité. Certes, dans ce cas, il y aurait quelques lignes supplémentaires mais encore loin d'être "extrêmement difficile"
Byron Coetsee
@ByronCoetsee J'incluais l'utilisation de bibliothèques comme AppKit, etc. - mon point est que vous aurez besoin de savoir comment interagir avec les bibliothèques Objective C afin d'écrire tout ce qui est utile dans Swift.
Matt Gibson
Voir la réponse d'alamofire - stackoverflow.com/a/46562290/7576100
Jack

Réponses:

228

Comme mentionné dans les commentaires, bien qu'il soit possible d'utiliser les bibliothèques Objective-C dans Swift, je voulais une solution Swift plus pure. La classe d'accessibilité Apple existante et d'autres bibliothèques tierces me semblaient trop compliquées à traduire en Swift. J'ai cherché un peu plus sur Google et je suis tombé sur cet article qui montre une méthode simple pour vérifier la disponibilité du réseau. J'ai décidé de traduire ceci en Swift. J'ai rencontré de nombreux problèmes, mais grâce à Martin R de StackOverflow, j'ai réussi à les résoudre et enfin à obtenir une solution viable dans Swift. Voici le 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
    }

}

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

Cela fonctionne pour les connexions 3G et WiFi. Je l'ai également téléchargé sur mon GitHub avec un exemple fonctionnel.

Isuru
la source
7
Merci pour la réponse rapide (sans jeu de mots). Le MIT ou Apache serait idéal - merci!
Andrew Ebling
4
Terminé. Je l'ai changé en MIT.
Isuru
11
J'ai trouvé un autre problème, si la 3G est activée mais que je n'ai plus de capacité de données, elle isConnectedToNetworkretourne true, mais je ne peux pas appeler mon service Web
János
11
Comme @Isuru l'a dit, ceci est basé sur stackoverflow.com/a/25623647/1187415 , qui a maintenant été mis à jour pour Swift 2.
Martin R
2
@ János: La définition d'un rappel de notification est désormais possible avec Swift 2, voir la réponse mise à jour stackoverflow.com/a/27142665/1187415 .
Martin R
16

Je te donne un meilleur moyen ...

Vous devez créer une classe avec ce 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
  }
}

Et puis, vous pouvez vérifier la connexion Internet n'importe où dans votre projet en utilisant ce code:

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

Très facile!

* Cette méthode est basée sur la réponse de Vikram Pote!

Dmitry
la source
15
Veuillez noter que vous ne devez pas utiliser cette méthode au-dessus de celle utilisée ci-dessus. Dans les applications qui nécessitent une connectivité constante, une vérification de réponse comme cette méthode entraînera le blocage de l'application dans des situations où votre connectivité Internet est mauvaise (c'est-à-dire sur Edge / GPRS). Veuillez ne pas utiliser cette solution !!
Imran Ahmed
7
Mauvaise façon 1) Besoin d'un coup supplémentaire sur le serveur chaque fois 2) google.com peut également être en panne
Vijay Singh Rana
2
1. Oui, cette méthode nécessite un accès supplémentaire au serveur à chaque fois, mais cela donne une garantie à 100% que l'Internet est disponible ... il y a des moments où l'appareil est connecté à un réseau wifi mais ne fournit pas d'accès Internet! Dans cette situation, cette manière détermine le manque d'accès à Internet ... d'autres moyens - non! 2. Vous pouvez utiliser votre propre serveur à la place google.com ... Cela était à l'origine destiné ...
Dmitry
1
mauvaise solution, tueur de connexion.
gokhanakkurt
2
gokhanakkurt, s'il vous plaît, suggérez une autre solution qui garantit que l'Internet fonctionne à 100%
Dmitry
15

Pour Swift 3.1 (iOS 10.1)

Si vous souhaitez faire la distinction entre le type de réseau (c'est-à-dire WiFi ou WWAN):

Vous pouvez utiliser:

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

Voici toute la classe d'accessibilité qui distingue les types de réseau:

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
la source
fonctionne bien à partir du 3 décembre 2016, iOS 10 et swift 3.1, merci!
joey
Bonjour, si nous voulons différencier la connexion Wifi / 3G / Mobile-Data / 4G pour cela comment nous pouvons nous identifier.
6

Puisque sendSynchronousRequest est obsolète, j'ai essayé ceci mais 'return Status' a été appelé avant la fin de la réponse.

Cette réponse fonctionne bien cependant, vérifiez la connexion Internet avec Swift

Voici ce que j'ai essayé de toute façon:

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
    }
}
Sarah
la source
J'ai aimé et utilisé la vôtre. Mais j'ai ajouté un combiné avec cette réponse: stackoverflow.com/a/34591379 aka. J'ai ajouté un sémaphore .. J'attends donc que la tâche se termine.
Bjqn
6

SWIFT 3: Vérifie wifi et internet connexion:

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
la source
2
public func isConnectedToNetwork() {...}doit être remplacé par class func isConnectedToNetwork{...}pour votre cas d'utilisation.
keverly
4

Vous pouvez également utiliser la réponse ci-dessous.

    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
la source
Merci! J'ai obtenu une correction automatique de la réponse en tant que NSHTTPURLResponse? pour répondre comme! NSHTTPURLResponse? dans Swift 1.2.
Francis Jervis
1

SWIFT 3: vérifier la connexion 3G et 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()
}
Włodzimierz Woźniak
la source
Ce n'est pas une manière préférée. Et si, à un moment donné dans le futur, le lien Web fourni cesse de répondre ou est en panne. Je recommanderais d'utiliser le framework Apple SystemConfiguration pour cela. Voir la réponse ci-dessus.
Abdul Yasin
1

Pour 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
la source
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)
}
Keshav Gera
la source