Überprüfen Sie die Verfügbarkeit der Internetverbindung in Swift

107

Gibt es eine Möglichkeit zu überprüfen, ob die Internetverbindung mit Swift verfügbar ist?

Ich weiß, dass es viele Bibliotheken von Drittanbietern gibt, die dies tun, aber alle sind in Objective-C geschrieben. Ich suche eine schnelle Alternative.

Isuru
quelle
5
Einer der großen Vorteile von Swift ist die gute Integration in Objective-C (und Bibliotheken davon).
user2864740
Tatsächlich. Welche Probleme haben Sie bei der Verwendung einer der vorhandenen Bibliotheken? Es ist ziemlich einfach, eine Objective C-Bibliothek von Swift zu verwenden, und es wird sich als äußerst schwierig für Sie erweisen, irgendeine Art von App in Swift zu schreiben, wenn Sie dies nicht können.
Matt Gibson
1
@MattGibson Fast alles, was Sie in ObjC tun können, kann relativ einfach in Swift erledigt werden. Zugegeben, in diesem Fall würde es ein paar zusätzliche Zeilen geben, aber immer noch weit entfernt von "extrem schwierig"
Byron Coetsee
@ByronCoetsee Ich habe Bibliotheken wie AppKit usw. verwendet. Mein Punkt ist, dass Sie wissen müssen, wie Sie mit Objective C-Bibliotheken interagieren, um in Swift nützliche Informationen zu schreiben.
Matt Gibson
Siehe alamofire Antwort - stackoverflow.com/a/46562290/7576100
Jack

Antworten:

227

Wie in den Kommentaren erwähnt, wollte ich eine reinere Swift-Lösung, obwohl es möglich ist, Objective-C-Bibliotheken in Swift zu verwenden. Die vorhandene Apple Reachability-Klasse und andere Bibliotheken von Drittanbietern schienen mir zu kompliziert, um sie in Swift zu übersetzen. Ich habe noch ein bisschen gegoogelt und bin auf diesen Artikel gestoßen, der eine einfache Methode zum Überprüfen der Netzwerkverfügbarkeit zeigt. Ich machte mich daran, dies in Swift zu übersetzen. Ich habe viele Probleme gelöst, aber dank Martin R von StackOverflow habe ich es geschafft, sie zu beheben und endlich eine praktikable Lösung in Swift zu finden. Hier ist der 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
    }

}

Für 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)
    }
}

Dies funktioniert sowohl für 3G- als auch für WiFi-Verbindungen. Ich habe es auch mit einem funktionierenden Beispiel auf meinen GitHub hochgeladen .

Isuru
quelle
7
Danke für die schnelle Antwort (kein Wortspiel beabsichtigt). MIT oder Apache wären ideal - danke!
Andrew Ebling
4
Getan. Es wurde in MIT geändert.
Isuru
11
Ich habe ein anderes Problem gefunden: Wenn 3G aktiviert ist , ich aber keine Datenkapazität mehr habe, wird isConnectedToNetworktrue zurückgegeben, aber ich kann meinen Webdienst nicht anrufen
János
11
Wie @Isuru sagte, basiert dies auf stackoverflow.com/a/25623647/1187415 , das jetzt für Swift 2 aktualisiert wurde.
Martin R
2
@ János: Das Festlegen eines Benachrichtigungsrückrufs ist jetzt mit Swift 2 möglich, siehe aktualisierte Antwort stackoverflow.com/a/27142665/1187415 .
Martin R
16

Ich gebe dir einen besseren Weg ...

Sie müssen eine Klasse mit diesem Code erstellen

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

Mit diesem Code können Sie die Internetverbindung an einer beliebigen Stelle in Ihrem Projekt überprüfen:

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

Sehr leicht!

* Dieser Weg basiert auf der Antwort von Vikram Pote!

Dmitry
quelle
15
Bitte beachten Sie, dass Sie sollten nicht diese Methode über die oben verwendet verwenden. In Anwendungen, die eine konstante Konnektivität erfordern, führt eine Antwortprüfung wie diese Methode dazu, dass die App in Situationen hängt, in denen Ihre Internetverbindung schlecht ist (z. B. bei Edge / GPRS). Bitte benutzen Sie diese Lösung nicht !!
Imran Ahmed
7
Schlechter Weg 1) Benötigen Sie zusätzliche Treffer für den Server jede Zeit 2) google.com kann auch ausgefallen sein
Vijay Singh Rana
2
1. Ja, auf diese Weise muss der Server jedes Mal zusätzlich getroffen werden, aber es gibt eine 100% ige Garantie dafür, dass das Internet verfügbar ist. Es gibt Zeiten, in denen das Gerät mit einem WLAN-Netzwerk verbunden ist, aber keinen Internetzugang bietet! In dieser Situation wird auf diese Weise der fehlende Zugang zum Internet festgestellt ... auf andere Weise - nein! 2. Sie können stattdessen Ihren eigenen Server verwenden google.com ... Dies war ursprünglich gemeint ...
Dmitry
1
schlechte Lösung, Verbindungskiller.
Gokhanakkurt
2
Gokhanakkurt, bitte schlagen Sie eine andere Lösung vor, die sicherstellt, dass das Internet zu 100% funktioniert
Dmitry
15

Für Swift 3.1 (iOS 10.1)

Wenn Sie zwischen dem Netzwerktyp (z. B. WLAN oder WWAN) unterscheiden möchten:

Sie können verwenden:

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

Hier ist die gesamte Erreichbarkeitsklasse, die zwischen Netzwerktypen unterschied:

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
quelle
funktioniert gut ab 3. Dezember 2016, iOS 10 und Swift 3.1, danke!
Joey
Hallo, wenn wir die Wifi / 3G / Mobile-Data / 4G-Verbindung danach unterscheiden wollen, wie wir sie identifizieren können.
6

Da sendSynchronousRequest veraltet ist, habe ich dies versucht, aber 'return Status' wurde aufgerufen, bevor die Antwort beendet war.

Diese Antwort funktioniert jedoch gut. Überprüfen Sie, ob eine Internetverbindung mit Swift besteht

Folgendes habe ich trotzdem versucht:

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
quelle
Ich mochte und benutzte deine Lösung. Aber ich habe eine Kombination mit dieser Antwort hinzugefügt: stackoverflow.com/a/34591379 aka. Ich habe ein Semaphor hinzugefügt. Also warte ich, bis die Aufgabe beendet ist.
Bjqn
6

SWIFT 3: Überprüft die WLAN- und Internetverbindung :

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

VERWENDUNG:

if Reachability.isConnectedToNetwork() == true {
    print("Connected to the internet")
    //  Do something
} else {
    print("No internet connection")
    //  Do something
}
Gilad Brunfman
quelle
2
public func isConnectedToNetwork() {...}sollte class func isConnectedToNetwork{...}für Ihren Anwendungsfall geändert werden.
keverly
4

Sie können auch die folgende Antwort verwenden.

    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
quelle
Vielen Dank! Ich habe eine automatische Korrektur von der Antwort als NSHTTPURLResponse? zu antworten als! NSHTTPURLResponse? in Swift 1.2.
Francis Jervis
1

SWIFT 3: Überprüfen Sie die 3G- und Wi-Fi-Verbindung

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
quelle
Dies ist kein bevorzugter Weg. Was ist, wenn der bereitgestellte Weblink zu einem späteren Zeitpunkt nicht mehr reagiert oder nicht mehr funktioniert? Ich würde empfehlen, hierfür das Apple SystemConfiguration Framework zu verwenden. Siehe die obige Antwort.
Abdul Yasin
1

Für 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
quelle
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
quelle