Sprawdź połączenie internetowe za pomocą Swift


251

Kiedy próbuję sprawdzić połączenie internetowe na moim iPhonie, pojawia się mnóstwo błędów. Czy ktoś może mi pomóc to naprawić?

Kod:

import Foundation
import SystemConfiguration

public class Reachability {

class func isConnectedToNetwork() -> Bool {

    var zeroAddress = sockaddr_in()
    zeroAddress.sin_len = UInt8(sizeofValue(zeroAddress))
    zeroAddress.sin_family = sa_family_t(AF_INET)

    let defaultRouteReachability = withUnsafePointer(&zeroAddress) {
        SCNetworkReachabilityCreateWithAddress(nil, UnsafePointer($0))
    }

    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) ? true : false
}

}

Błędy w kodzie:

Błędy

Jeśli jest nieczytelny, błąd 1 mówi:

„Int” nie jest konwertowany na „SCNetworkReachabilityFlags”

Błąd 2 i 3:

Nie można znaleźć przeciążenia dla parametru „init”, które akceptuje podane argumenty


1
Kod wygląda podobnie do tego, co tutaj zasugerowałem: stackoverflow.com/a/25623647/1187415 , więc zaktualizowałem go dla Swift 2.
Martin R

2
Mam tutaj w pełni działającą implementację Swift 2 Reachability… github.com/ashleymills/Reachability.swift - Zapraszam do skorzystania z tego jako odniesienia.
Ashley Mills,

1
stackoverflow.com/a/25623647/1187415 Jest teraz zaktualizowany do Swift 3, Xcode 8 beta 6.
Martin R

1
Apple zapewnia oficjalną próbkę Swift , którą można uzyskać na CocoaPods . Jest kompatybilny z każdym projektem Swift.
Cœur

Odpowiedzi:


368

Aby rozwiązać problem 4G wymieniony w komentarzach, wykorzystałem implementację osiągalności @AshleyMills jako odniesienie i przepisałem Reachability for Swift 3.1:

zaktualizowano: Xcode 10.1 • Swift 4 lub nowszy


Plik Reachability.swift

import Foundation
import SystemConfiguration

class Reachability {
    var hostname: String?
    var isRunning = false
    var isReachableOnWWAN: Bool
    var reachability: SCNetworkReachability?
    var reachabilityFlags = SCNetworkReachabilityFlags()
    let reachabilitySerialQueue = DispatchQueue(label: "ReachabilityQueue")
    init(hostname: String) throws {
        guard let reachability = SCNetworkReachabilityCreateWithName(nil, hostname) else {
            throw Network.Error.failedToCreateWith(hostname)
        }
        self.reachability = reachability
        self.hostname = hostname
        isReachableOnWWAN = true
        try start()
    }
    init() throws {
        var zeroAddress = sockaddr_in()
        zeroAddress.sin_len = UInt8(MemoryLayout<sockaddr_in>.size)
        zeroAddress.sin_family = sa_family_t(AF_INET)
        guard let reachability = withUnsafePointer(to: &zeroAddress, {
            $0.withMemoryRebound(to: sockaddr.self, capacity: 1) {
                SCNetworkReachabilityCreateWithAddress(nil, $0)
            }
        }) else {
            throw Network.Error.failedToInitializeWith(zeroAddress)
        }
        self.reachability = reachability
        isReachableOnWWAN = true
        try start()
    }
    var status: Network.Status {
        return  !isConnectedToNetwork ? .unreachable :
                isReachableViaWiFi    ? .wifi :
                isRunningOnDevice     ? .wwan : .unreachable
    }
    var isRunningOnDevice: Bool = {
        #if targetEnvironment(simulator)
            return false
        #else
            return true
        #endif
    }()
    deinit { stop() }
}

extension Reachability {

    func start() throws {
        guard let reachability = reachability, !isRunning else { return }
        var context = SCNetworkReachabilityContext(version: 0, info: nil, retain: nil, release: nil, copyDescription: nil)
        context.info = Unmanaged<Reachability>.passUnretained(self).toOpaque()
        guard SCNetworkReachabilitySetCallback(reachability, callout, &context) else { stop()
            throw Network.Error.failedToSetCallout
        }
        guard SCNetworkReachabilitySetDispatchQueue(reachability, reachabilitySerialQueue) else { stop()
            throw Network.Error.failedToSetDispatchQueue
        }
        reachabilitySerialQueue.async { self.flagsChanged() }
        isRunning = true
    }

    func stop() {
        defer { isRunning = false }
        guard let reachability = reachability else { return }
        SCNetworkReachabilitySetCallback(reachability, nil, nil)
        SCNetworkReachabilitySetDispatchQueue(reachability, nil)
        self.reachability = nil
    }

    var isConnectedToNetwork: Bool {
        return isReachable &&
               !isConnectionRequiredAndTransientConnection &&
               !(isRunningOnDevice && isWWAN && !isReachableOnWWAN)
    }

    var isReachableViaWiFi: Bool {
        return isReachable && isRunningOnDevice && !isWWAN
    }

    /// Flags that indicate the reachability of a network node name or address, including whether a connection is required, and whether some user intervention might be required when establishing a connection.
    var flags: SCNetworkReachabilityFlags? {
        guard let reachability = reachability else { return nil }
        var flags = SCNetworkReachabilityFlags()
        return withUnsafeMutablePointer(to: &flags) {
            SCNetworkReachabilityGetFlags(reachability, UnsafeMutablePointer($0))
            } ? flags : nil
    }

    /// compares the current flags with the previous flags and if changed posts a flagsChanged notification
    func flagsChanged() {
        guard let flags = flags, flags != reachabilityFlags else { return }
        reachabilityFlags = flags
        NotificationCenter.default.post(name: .flagsChanged, object: self)
    }

    /// The specified node name or address can be reached via a transient connection, such as PPP.
    var transientConnection: Bool { return flags?.contains(.transientConnection) == true }

    /// The specified node name or address can be reached using the current network configuration.
    var isReachable: Bool { return flags?.contains(.reachable) == true }

    /// The specified node name or address can be reached using the current network configuration, but a connection must first be established. If this flag is set, the kSCNetworkReachabilityFlagsConnectionOnTraffic flag, kSCNetworkReachabilityFlagsConnectionOnDemand flag, or kSCNetworkReachabilityFlagsIsWWAN flag is also typically set to indicate the type of connection required. If the user must manually make the connection, the kSCNetworkReachabilityFlagsInterventionRequired flag is also set.
    var connectionRequired: Bool { return flags?.contains(.connectionRequired) == true }

    /// The specified node name or address can be reached using the current network configuration, but a connection must first be established. Any traffic directed to the specified name or address will initiate the connection.
    var connectionOnTraffic: Bool { return flags?.contains(.connectionOnTraffic) == true }

    /// The specified node name or address can be reached using the current network configuration, but a connection must first be established.
    var interventionRequired: Bool { return flags?.contains(.interventionRequired) == true }

    /// The specified node name or address can be reached using the current network configuration, but a connection must first be established. The connection will be established "On Demand" by the CFSocketStream programming interface (see CFStream Socket Additions for information on this). Other functions will not establish the connection.
    var connectionOnDemand: Bool { return flags?.contains(.connectionOnDemand) == true }

    /// The specified node name or address is one that is associated with a network interface on the current system.
    var isLocalAddress: Bool { return flags?.contains(.isLocalAddress) == true }

    /// Network traffic to the specified node name or address will not go through a gateway, but is routed directly to one of the interfaces in the system.
    var isDirect: Bool { return flags?.contains(.isDirect) == true }

    /// The specified node name or address can be reached via a cellular connection, such as EDGE or GPRS.
    var isWWAN: Bool { return flags?.contains(.isWWAN) == true }

    /// The specified node name or address can be reached using the current network configuration, but a connection must first be established. If this flag is set
    /// The specified node name or address can be reached via a transient connection, such as PPP.
    var isConnectionRequiredAndTransientConnection: Bool {
        return (flags?.intersection([.connectionRequired, .transientConnection]) == [.connectionRequired, .transientConnection]) == true
    }
}

func callout(reachability: SCNetworkReachability, flags: SCNetworkReachabilityFlags, info: UnsafeMutableRawPointer?) {
    guard let info = info else { return }
    DispatchQueue.main.async {
        Unmanaged<Reachability>
            .fromOpaque(info)
            .takeUnretainedValue()
            .flagsChanged()
    }
}

extension Notification.Name {
    static let flagsChanged = Notification.Name("FlagsChanged")
}

struct Network {
    static var reachability: Reachability!
    enum Status: String {
        case unreachable, wifi, wwan
    }
    enum Error: Swift.Error {
        case failedToSetCallout
        case failedToSetDispatchQueue
        case failedToCreateWith(String)
        case failedToInitializeWith(sockaddr_in)
    }
}

Stosowanie

Zainicjuj go w metodzie AppDelegate.swift didFinishLaunchingWithOptions i obsłuż wszystkie ewentualne błędy:

import UIKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
    var window: UIWindow?
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        do {
            try Network.reachability = Reachability(hostname: "www.google.com")
        }
        catch {
            switch error as? Network.Error {
            case let .failedToCreateWith(hostname)?:
                print("Network error:\nFailed to create reachability object With host named:", hostname)
            case let .failedToInitializeWith(address)?:
                print("Network error:\nFailed to initialize reachability object With address:", address)
            case .failedToSetCallout?:
                print("Network error:\nFailed to set callout")
            case .failedToSetDispatchQueue?:
                print("Network error:\nFailed to set DispatchQueue")
            case .none:
                print(error)
            }
        }
        return true
    }
}

I przykład kontrolera widoku:

import UIKit
class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        NotificationCenter.default
            .addObserver(self,
                         selector: #selector(statusManager),
                         name: .flagsChanged,
                         object: nil)
        updateUserInterface()
    }
    func updateUserInterface() {
        switch Network.reachability.status {
        case .unreachable:
            view.backgroundColor = .red
        case .wwan:
            view.backgroundColor = .yellow
        case .wifi:
            view.backgroundColor = .green
        }
        print("Reachability Summary")
        print("Status:", Network.reachability.status)
        print("HostName:", Network.reachability.hostname ?? "nil")
        print("Reachable:", Network.reachability.isReachable)
        print("Wifi:", Network.reachability.isReachableViaWiFi)
    }
    @objc func statusManager(_ notification: Notification) {
        updateUserInterface()
    }
}

Przykładowy projekt


2
Musisz usunąć `== 0` z, if SCNetworkReachabilityGetFlags(…)ponieważ xCode zwraca Bool w jego najnowszej wersji.
Melvin,

64
To NIE jest poprawne, jak wspomniano @NickM. NIE BĘDZIE DZIAŁAĆ DLA POŁĄCZEŃ KOMÓRKOWYCH . Nie używaj tego. Dziwi mnie, że ma tyle głosów, może to nowość na iOS 9 ... ale nie sądzę.
Jordan Smith

1
Nie działa na IOS9, okazało się to bardzo trudne - aplikacja w sklepie ... więc sądzę, że nawet jeśli nie jest w 100% dokładna i działa na niektóre, w najlepszym razie jest niespójna, więc każdy, kto chce zaryzykować, może również chcieć obstawiać konia lub pieska, jeśli mają szczęście.
Nick M

2
@NickM - to wyjaśnia, dlaczego tak wiele głosów. @ Leo dobrym pomysłem może być aktualizacja odpowiedzi na iOS 9, aby uratować inne osoby wpadające w tę samą pułapkę. Mogę potwierdzić, że nie działa (przynajmniej w niektórych sytuacjach) na iOS 9 ... zmiana na github.com/ashleymills/Reachability.swift działa jednak dobrze.
Jordan Smith

1
Tak, widzę, że wynosił w oddziale iOS10
Ace Green

224

W przypadku Swift 3, Swift 4 (współpracujący z siecią komórkową i Wi-Fi):

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(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 = SCNetworkReachabilityFlags(rawValue: 0)
        if SCNetworkReachabilityGetFlags(defaultRouteReachability!, &flags) == false {
            return false
        }

        /* Only Working for WIFI
        let isReachable = flags == .reachable
        let needsConnection = flags == .connectionRequired

        return isReachable && !needsConnection
        */

        // Working for Cellular and WIFI
        let isReachable = (flags.rawValue & UInt32(kSCNetworkFlagsReachable)) != 0
        let needsConnection = (flags.rawValue & UInt32(kSCNetworkFlagsConnectionRequired)) != 0
        let ret = (isReachable && !needsConnection)

        return ret

    }
}

Stosowanie:

if Reachability.isConnectedToNetwork(){
    print("Internet Connection Available!")
}else{
    print("Internet Connection not Available!")
}

3
To rozwiązanie + CoreTelephony (CTTelephonyNetworkInfo (). CurrentRadioAccessTechnology) jest najlepszym rozwiązaniem do uzyskania bieżącego typu sieci i bez konieczności polegania na bibliotekach stron trzecich.
Alejandro Jiménez Agudo

3
Działa na komórkowej i WiFi z szybkim 3.1! Działa testowane na iPhone'ach 6 i 7. Jeśli Cellular Off pojawia się komunikat „.. Połączenie niedostępne”. Jeśli włączę tryb samolotowy, otrzymam to samo „... niedostępne”. Jeśli wyłączę komórkę i włączę Wi-Fi, pojawi się „.. Połączenie dostępne”, a na koniec, jeśli wyłączę Wi-Fi i włączę sieć komórkową, dostanę „.. Połączenie dostępne”. Uwaga: moje połączenie komórkowe to LTE
Brian,

1
Cześć, to nie działa na iOS 11, tryb samolotowy na urządzeniu fizycznym. Po ustawieniu na tryb samolotowy funkcja IsReachable nadal jest prawdziwa ... masz pojęcie, dlaczego?
Lawrence Tan

3
Działa to idealnie dla mnie we wszystkich scenariuszach. Jest również testowany z iOS 12 działającym na iPhonie 6.
r3dm4n

3
To nie działa, jeśli mam połączenie z siecią Wi-Fi bez połączenia z Internetem
Nathan Barreto,

58

Utwórz nowy plik Swift w swoim projekcie, nazwij go Reachability.swift. Wytnij i wklej do niego poniższy kod, aby utworzyć klasę.

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(kCFAllocatorDefault, UnsafePointer($0))
        }

        var flags: SCNetworkReachabilityFlags = SCNetworkReachabilityFlags(rawValue: 0)
        if SCNetworkReachabilityGetFlags(defaultRouteReachability!, &flags) == false {
             return false
        }

        let isReachable = flags == .Reachable
        let needsConnection = flags == .ConnectionRequired

        return isReachable && !needsConnection

    }
}

Możesz sprawdzić połączenie internetowe w dowolnym miejscu swojego projektu, używając tego kodu:

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

Jeśli użytkownik nie jest podłączony do Internetu, możesz wyświetlić mu okno dialogowe z ostrzeżeniem, aby je powiadomić.

if Reachability.isConnectedToNetwork() {
    println("Internet connection OK")
} else {
    println("Internet connection FAILED")
    var alert = UIAlertView(title: "No Internet Connection", message: "Make sure your device is connected to the internet.", delegate: nil, cancelButtonTitle: "OK")
    alert.show()
}

Wyjaśnienie:

Tworzymy klasę publiczną wielokrotnego użytku i metodę, której można użyć w dowolnym miejscu projektu, aby sprawdzić łączność z Internetem. Wymagamy dodania ram Foundation i System Configuration.

W klasie publicznej Reachability metoda isConnectedToNetwork() -> Bool { }zwróci wartość bool dotyczącą łączności internetowej. Używamy pętli if, aby wykonać wymagane działania na obudowie. Mam nadzieję, że to wystarczy. Twoje zdrowie!


4
Podając rozwiązanie, spróbuj je trochę wyjaśnić. Podanie rozwiązania nie jest ważne, ale sprawienie, by czytelnicy zrozumieli rozwiązanie, a jego koncepcja jest ważniejsza.
G.Abhisek

1
Jestem nowy w programowaniu na iOS. Dlaczego w tym celu musimy zainicjować strukturę C? W jakich przypadkach możemy użyć struktur C?
G.Abhisek

1
ustawiłem to na „viewdidload” tylko w celu przetestowania. Otwieram aplikację i OK, mam internet, ale kiedy strzelam do Internetu, nadal pokazuje mi, że mam internet ... to jest trwałe? czy muszę za każdym razem „wywoływać akcję”?
Daniel Arantes Loverde

16
@AlvinGeorge NIE działa to po podłączeniu do sieci komórkowej. Działa to tylko podczas korzystania z Wi-Fi. Dla kogokolwiek innego - nie chcesz tego używać w swojej aplikacji! @ Alvin - czy mogę zasugerować aktualizację odpowiedzi lub jej usunięcie? Z 19 głosami jest bardzo mylące dla innych programistów, którzy mogą wpaść w tę samą pułapkę.
Jordan Smith

@Jordan: Ta metoda używa domyślnej struktury Apple dla statusu sieci. Może się to zmienić w nowych wersjach iOS. Dlatego zalecam sprawdzenie i wdrożenie klasy osiągalności Ashely Mill. Zrobiłem implementację bez zależności i udostępniłem powyższy link. Proszę spojrzeć.
AG

56

Jeśli ktoś już korzysta z Alamofire, to -

struct Connectivity {
  static let sharedInstance = NetworkReachabilityManager()!
  static var isConnectedToInternet:Bool {
      return self.sharedInstance.isReachable
    }
}

Stosowanie:

if Connectivity.isConnectedToInternet {
     print("Connected")
 } else {
     print("No Internet")
}

1
z dokumentacji Alamofire:> Klasa NetworkReachabilityManager nasłuchuje zmian osiągalności hostów i adresów dla interfejsów sieci WWAN i WiFi. > Osiągalność może być wykorzystana do ustalenia podstawowych informacji o tym, dlaczego operacja sieci nie powiodła się, lub do ponownej próby żądań sieciowych po ustanowieniu połączenia. Nie należy go używać, aby uniemożliwić użytkownikowi zainicjowanie żądania sieciowego, ponieważ możliwe jest, że początkowe żądanie może być wymagane w celu ustalenia osiągalności.
fespinozacast

1
@ fespinozacast dobrze możesz sprawdzić kod połączenia internetowego w NetworkReachabilityManager.swift , co jest w porządku :)
Jack

15

Sprawdziłem wdrożenie klasy osiągalności Ashley Mill bez Cocoa Pods / Dependancy Manager. Chodzi o to, aby zależność od osiągalności była wolna w projekcie.

Xcode 7.2 - Swift 2.1

1) https://github.com/ashleymills/Reachability.swift . Pobierz dodaj klasę osiągalności do projektu.

Uwaga: Podczas dodawania upewnij się, że zaznaczone jest „skopiuj elementy w razie potrzeby”.

2) Utwórz klasę AppManager.swift. Ta klasa będzie służyć jako klasa modelu publicznego, do której zostaną dodane publiczne metody i dane, które można wykorzystać w dowolnym VC.

//  AppManager.swift

import UIKit
import Foundation

class AppManager: NSObject{
    var delegate:AppManagerDelegate? = nil
    private var _useClosures:Bool = false
    private var reachability: Reachability?
    private var _isReachability:Bool = false
    private var _reachabiltyNetworkType :String?

    var isReachability:Bool {
        get {return _isReachability}
    }  
   var reachabiltyNetworkType:String {
    get {return _reachabiltyNetworkType! }
   }   




    // Create a shared instance of AppManager
    final  class var sharedInstance : AppManager {
        struct Static {
            static var instance : AppManager?
        }
        if !(Static.instance != nil) {
            Static.instance = AppManager()

        }
        return Static.instance!
    }

    // Reachability Methods
    func initRechabilityMonitor() {
        print("initialize rechability...")
        do {
            let reachability = try Reachability.reachabilityForInternetConnection()
            self.reachability = reachability
        } catch ReachabilityError.FailedToCreateWithAddress(let address) {
            print("Unable to create\nReachability with address:\n\(address)")
            return
        } catch {}
        if (_useClosures) {
            reachability?.whenReachable = { reachability in
                self.notifyReachability(reachability)
            }
            reachability?.whenUnreachable = { reachability in
                self.notifyReachability(reachability)
            }
        } else {
            self.notifyReachability(reachability!)
        }

        do {
            try reachability?.startNotifier()
        } catch {
            print("unable to start notifier")
            return
        }


    }        
    private func notifyReachability(reachability:Reachability) {
        if reachability.isReachable() {
            self._isReachability = true

//Determine Network Type 
      if reachability.isReachableViaWiFi() {   
        self._reachabiltyNetworkType = CONNECTION_NETWORK_TYPE.WIFI_NETWORK.rawValue
      } else {
        self._reachabiltyNetworkType = CONNECTION_NETWORK_TYPE.WWAN_NETWORK.rawValue
      }

        } else {
            self._isReachability = false
self._reachabiltyNetworkType = CONNECTION_NETWORK_TYPE.OTHER.rawValue

        }

        NSNotificationCenter.defaultCenter().addObserver(self, selector: "reachabilityChanged:", name: ReachabilityChangedNotification, object: reachability)
    }
    func reachabilityChanged(note: NSNotification) {
        let reachability = note.object as! Reachability
        dispatch_async(dispatch_get_main_queue()) {
            if (self._useClosures) {
                self.reachability?.whenReachable = { reachability in
                    self.notifyReachability(reachability)
                }
                self.reachability?.whenUnreachable = { reachability in
                    self.notifyReachability(reachability)
                }
            } else {
                self.notifyReachability(reachability)
            }
            self.delegate?.reachabilityStatusChangeHandler(reachability)
        }
    }
    deinit {
        reachability?.stopNotifier()
        if (!_useClosures) {
            NSNotificationCenter.defaultCenter().removeObserver(self, name: ReachabilityChangedNotification, object: nil)
        }
    }
}

3) Stwórz delegowaną klasę. Używam metody delegowania, aby powiadomić o stanie łączności.

//  Protocols.swift

import Foundation
@objc protocol AppManagerDelegate:NSObjectProtocol {

    func reachabilityStatusChangeHandler(reachability:Reachability)
}

4) Utwórz klasę nadrzędną UIViewController (metoda dziedziczenia). Klasa nadrzędna ma metody, które są dostępne dla wszystkich potomnych VC.

//  UIappViewController.swift

    import UIKit

    class UIappViewController: UIViewController,AppManagerDelegate {
        var manager:AppManager = AppManager.sharedInstance

        override func viewDidLoad() {
            super.viewDidLoad()
            manager.delegate = self
        }
        override func didReceiveMemoryWarning() {
            super.didReceiveMemoryWarning()
        }
        func reachabilityStatusChangeHandler(reachability: Reachability) {
            if reachability.isReachable() {
                print("isReachable")
            } else {
                print("notReachable")
            }
        }
    }

5) Uruchom monitorowanie połączeń internetowych w czasie rzeczywistym w AppDelegate.

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
    AppManager.sharedInstance.initRechabilityMonitor()
return true
}

6) Dodałem AppReference Swift File Name do przechowywania stałych wartości wyliczania.

//  AppReference.swift

import Foundation

enum CONNECTION_NETWORK_TYPE : String {

  case WIFI_NETWORK = "Wifi"
  case WWAN_NETWORK = "Cellular"
  case OTHER = "Other"

}

7) W ViewController (np. Chcesz wywołać API tylko wtedy, gdy sieć jest dostępna)

//  ViewController.swift

        import UIKit

class ViewController: UIappViewController {
  var reachability:Reachability?

  override func viewDidLoad() {
    super.viewDidLoad()
    manager.delegate = self

    if(AppManager.sharedInstance.isReachability)
    {
      print("net available")
      //call API from here.

    } else {
      dispatch_async(dispatch_get_main_queue()) {
        print("net not available")
        //Show Alert
      }
    }


    //Determine Network Type
    if(AppManager.sharedInstance.reachabiltyNetworkType == "Wifi")
    {
      print(".Wifi")
    }
    else if (AppManager.sharedInstance.reachabiltyNetworkType == "Cellular")
    {
      print(".Cellular")
    }
    else {
      dispatch_async(dispatch_get_main_queue()) {
        print("Network not reachable")
      }
    }

  }
  override func viewWillAppear(animated: Bool) {
  }
  override func didReceiveMemoryWarning() {
  }
}

Próbkę można pobrać @ https://github.com/alvinreuben/Reachability-Sample

Aktualizacja do Swift 3.1- https://github.com/alvinvgeorge/Reachability-UpgradedToSwift3


W kroku 4 ... UIappViewController.swift, dlaczego potrzebujemy tej klasy !?
Learn2Code

UIappViewController.swift nie działa z UICollectionViewController, więc jeśli masz widok UICollectionViewController, nie możesz odziedziczyć UIappViewController !?
Learn2Code

12

Apple wprowadziło Network Framework w iOS12.

import Foundation
import Network

class NetworkReachability {

   var pathMonitor: NWPathMonitor!
   var path: NWPath?
   lazy var pathUpdateHandler: ((NWPath) -> Void) = { path in
    self.path = path
    if path.status == NWPath.Status.satisfied {
        print("Connected")
    } else if path.status == NWPath.Status.unsatisfied {
        print("unsatisfied")
    } else if path.status == NWPath.Status.requiresConnection {
        print("requiresConnection")
    } 
}

let backgroudQueue = DispatchQueue.global(qos: .background)

init() {
    pathMonitor = NWPathMonitor()
    pathMonitor.pathUpdateHandler = self.pathUpdateHandler
    pathMonitor.start(queue: backgroudQueue)
   } 

 func isNetworkAvailable() -> Bool {
        if let path = self.path {
           if path.status == NWPath.Status.satisfied {
            return true
          }
        }
       return false
   }
 }

ścieżka var: NWPath? jest zero. Jak zainicjować tę właściwość?
Vitya Shurapov

@VityaShurapov Przypisując ścieżkę, którą otrzymujesz w bloku pathUpdateHandler.
Yogendra Singh,

Wygląda to fantazyjnie, ale znalazłem (przynajmniej na symulatorze), że jeśli wyłączę następnie WiFi w laptopie, otrzymam oddzwonienie, ale mówi „niezadowolony”, a potem oddzwanianie nigdy nie jest wywoływane.
zaitsman

Gdy komórka włącza się / wyłącza, przewodnik uruchamia się tylko raz dla włączenia / wyłączenia. Kiedy WiFi włącza się / wyłącza, otrzymuję 2 identyczne wyzwalacze do włączania / wyłączania (wszystkie właściwości są identyczne). Dlaczego?
geohei

pathUpdateHandlerwprowadzi silne odniesienie do self, doda [weak self]do rozwiązania :)
Andrea de Marco,

11

Użyj tego dla Swift-5 +

import Foundation
import UIKit
import SystemConfiguration

public class InternetConnectionManager {


    private init() {

    }

    public static func isConnectedToNetwork() -> Bool {

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

                SCNetworkReachabilityCreateWithAddress(nil, $0)

            }

        }) else {

            return false
        }
        var flags = SCNetworkReachabilityFlags()
        if !SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags) {
            return false
        }
        let isReachable = (flags.rawValue & UInt32(kSCNetworkFlagsReachable)) != 0
        let needsConnection = (flags.rawValue & UInt32(kSCNetworkFlagsConnectionRequired)) != 0
        return (isReachable && !needsConnection)
    }

}

Stosowanie:

InternetConnectionManager.isConnectedToNetwork{
    print("Connected")
}else{
    print("Not Connected")
}

Lub Po prostu użyj tego, frameworkaby uzyskać więcejUtilities : Link


@ DocAsh59 :) Witamy! Miłego kodowania!
Jamil Hasnine Tamim

Nie rozumiem użycia tego. Kompilator wyświetla błąd „Argumenty przekazane do wywołania, które nie przyjmują argumentów”.
Roland Lariotte

1
@RolandLariotte Po prostu klasy w swoim projekcie o nazwie - „InternetConnectionManager”, a następnie zadzwoń z dowolnego miejsca!
Jamil Hasnine Tamim

Działa świetnie. Czy uważasz, że ten kod może być bardziej reaktywny, używając Połącz i zwracając AnyPublisher <Bool, Never>? Czy mógłbyś to napisać w ten sposób?
Roland Lariotte

@RolandLariotte Tak może być. Później napiszę inny kod. Dzięki i nie zapomnij o wsparciu! :)
Jamil Hasnine Tamim

7

Właśnie to wymyśliłem.

Xcode: 7.3.1, iOS 9.3.3

Używając ashleymills / Reachability.swift jako Reachability.swift w moim projekcie, stworzyłem następującą funkcję:

func hasConnectivity() -> Bool {
    do {
        let reachability: Reachability = try Reachability.reachabilityForInternetConnection()
        let networkStatus: Int = reachability.currentReachabilityStatus.hashValue

        return (networkStatus != 0)
    }
    catch {
        // Handle error however you please
        return false
    }
}

Po prostu zadzwoń hasConnectivity()tam, gdzie chcesz sprawdzić połączenie. Działa to zarówno w sieci Wi-Fi, jak i komórkowej.


Dodanie Ashleymills's Reachability.swift, aby ludzie nie musieli przemieszczać się między witrynami:

Copyright (c) 2014, Ashley Mills
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/

// Reachability.swift version 2.2beta2

import SystemConfiguration
import Foundation

public enum ReachabilityError: ErrorType {
    case FailedToCreateWithAddress(sockaddr_in)
    case FailedToCreateWithHostname(String)
    case UnableToSetCallback
    case UnableToSetDispatchQueue
}

public let ReachabilityChangedNotification = "ReachabilityChangedNotification"

func callback(reachability:SCNetworkReachability, flags: SCNetworkReachabilityFlags, info: UnsafeMutablePointer<Void>) {
    let reachability = Unmanaged<Reachability>.fromOpaque(COpaquePointer(info)).takeUnretainedValue()

    dispatch_async(dispatch_get_main_queue()) {
        reachability.reachabilityChanged(flags)
    }
}


public class Reachability: NSObject {

    public typealias NetworkReachable = (Reachability) -> ()
    public typealias NetworkUnreachable = (Reachability) -> ()

    public enum NetworkStatus: CustomStringConvertible {

        case NotReachable, ReachableViaWiFi, ReachableViaWWAN

        public var description: String {
            switch self {
            case .ReachableViaWWAN:
                return "Cellular"
            case .ReachableViaWiFi:
                return "WiFi"
            case .NotReachable:
                return "No Connection"
            }
        }
    }

    // MARK: - *** Public properties ***
    public var whenReachable: NetworkReachable?
    public var whenUnreachable: NetworkUnreachable?
    public var reachableOnWWAN: Bool
    public var notificationCenter = NSNotificationCenter.defaultCenter()

    public var currentReachabilityStatus: NetworkStatus {
        if isReachable() {
            if isReachableViaWiFi() {
                return .ReachableViaWiFi
            }
            if isRunningOnDevice {
                return .ReachableViaWWAN
            }
        }
        return .NotReachable
    }

    public var currentReachabilityString: String {
        return "\(currentReachabilityStatus)"
    }

    private var previousFlags: SCNetworkReachabilityFlags?

    // MARK: - *** Initialisation methods ***

    required public init(reachabilityRef: SCNetworkReachability) {
        reachableOnWWAN = true
        self.reachabilityRef = reachabilityRef
    }

    public convenience init(hostname: String) throws {

        let nodename = (hostname as NSString).UTF8String
        guard let ref = SCNetworkReachabilityCreateWithName(nil, nodename) else { throw ReachabilityError.FailedToCreateWithHostname(hostname) }

        self.init(reachabilityRef: ref)
    }

    public class func reachabilityForInternetConnection() throws -> Reachability {

        var zeroAddress = sockaddr_in()
        zeroAddress.sin_len = UInt8(sizeofValue(zeroAddress))
        zeroAddress.sin_family = sa_family_t(AF_INET)

        guard let ref = withUnsafePointer(&zeroAddress, {
            SCNetworkReachabilityCreateWithAddress(nil, UnsafePointer($0))
        }) else { throw ReachabilityError.FailedToCreateWithAddress(zeroAddress) }

        return Reachability(reachabilityRef: ref)
    }

    public class func reachabilityForLocalWiFi() throws -> Reachability {

        var localWifiAddress: sockaddr_in = sockaddr_in(sin_len: __uint8_t(0), sin_family: sa_family_t(0), sin_port: in_port_t(0), sin_addr: in_addr(s_addr: 0), sin_zero: (0, 0, 0, 0, 0, 0, 0, 0))
        localWifiAddress.sin_len = UInt8(sizeofValue(localWifiAddress))
        localWifiAddress.sin_family = sa_family_t(AF_INET)

        // IN_LINKLOCALNETNUM is defined in <netinet/in.h> as 169.254.0.0
        let address: UInt32 = 0xA9FE0000
        localWifiAddress.sin_addr.s_addr = in_addr_t(address.bigEndian)

        guard let ref = withUnsafePointer(&localWifiAddress, {
            SCNetworkReachabilityCreateWithAddress(nil, UnsafePointer($0))
        }) else { throw ReachabilityError.FailedToCreateWithAddress(localWifiAddress) }

        return Reachability(reachabilityRef: ref)
    }

    // MARK: - *** Notifier methods ***
    public func startNotifier() throws {

        guard !notifierRunning else { return }

        var context = SCNetworkReachabilityContext(version: 0, info: nil, retain: nil, release: nil, copyDescription: nil)
        context.info = UnsafeMutablePointer(Unmanaged.passUnretained(self).toOpaque())

        if !SCNetworkReachabilitySetCallback(reachabilityRef!, callback, &context) {
            stopNotifier()
            throw ReachabilityError.UnableToSetCallback
        }

        if !SCNetworkReachabilitySetDispatchQueue(reachabilityRef!, reachabilitySerialQueue) {
            stopNotifier()
            throw ReachabilityError.UnableToSetDispatchQueue
        }

        // Perform an intial check
        dispatch_async(reachabilitySerialQueue) { () -> Void in
            let flags = self.reachabilityFlags
            self.reachabilityChanged(flags)
        }

        notifierRunning = true
    }

    public func stopNotifier() {
        defer { notifierRunning = false }
        guard let reachabilityRef = reachabilityRef else { return }

        SCNetworkReachabilitySetCallback(reachabilityRef, nil, nil)
        SCNetworkReachabilitySetDispatchQueue(reachabilityRef, nil)
    }

    // MARK: - *** Connection test methods ***
    public func isReachable() -> Bool {
        let flags = reachabilityFlags
        return isReachableWithFlags(flags)
    }

    public func isReachableViaWWAN() -> Bool {

        let flags = reachabilityFlags

        // Check we're not on the simulator, we're REACHABLE and check we're on WWAN
        return isRunningOnDevice && isReachable(flags) && isOnWWAN(flags)
    }

    public func isReachableViaWiFi() -> Bool {

        let flags = reachabilityFlags

        // Check we're reachable
        if !isReachable(flags) {
            return false
        }

        // Must be on WiFi if reachable but not on an iOS device (i.e. simulator)
        if !isRunningOnDevice {
            return true
        }

        // Check we're NOT on WWAN
        return !isOnWWAN(flags)
    }

    // MARK: - *** Private methods ***
    private var isRunningOnDevice: Bool = {
        #if (arch(i386) || arch(x86_64)) && os(iOS)
            return false
        #else
            return true
        #endif
    }()

    private var notifierRunning = false
    private var reachabilityRef: SCNetworkReachability?
    private let reachabilitySerialQueue = dispatch_queue_create("uk.co.ashleymills.reachability", DISPATCH_QUEUE_SERIAL)

    private func reachabilityChanged(flags: SCNetworkReachabilityFlags) {

        guard previousFlags != flags else { return }

        if isReachableWithFlags(flags) {
            if let block = whenReachable {
                block(self)
            }
        } else {
            if let block = whenUnreachable {
                block(self)
            }
        }

        notificationCenter.postNotificationName(ReachabilityChangedNotification, object:self)

        previousFlags = flags
    }

    private func isReachableWithFlags(flags: SCNetworkReachabilityFlags) -> Bool {

        if !isReachable(flags) {
            return false
        }

        if isConnectionRequiredOrTransient(flags) {
            return false
        }

        if isRunningOnDevice {
            if isOnWWAN(flags) && !reachableOnWWAN {
                // We don't want to connect when on 3G.
                return false
            }
        }

        return true
    }

    // WWAN may be available, but not active until a connection has been established.
    // WiFi may require a connection for VPN on Demand.
    private func isConnectionRequired() -> Bool {
        return connectionRequired()
    }

    private func connectionRequired() -> Bool {
        let flags = reachabilityFlags
        return isConnectionRequired(flags)
    }

    // Dynamic, on demand connection?
    private func isConnectionOnDemand() -> Bool {
        let flags = reachabilityFlags
        return isConnectionRequired(flags) && isConnectionOnTrafficOrDemand(flags)
    }

    // Is user intervention required?
    private func isInterventionRequired() -> Bool {
        let flags = reachabilityFlags
        return isConnectionRequired(flags) && isInterventionRequired(flags)
    }

    private func isOnWWAN(flags: SCNetworkReachabilityFlags) -> Bool {
        #if os(iOS)
            return flags.contains(.IsWWAN)
        #else
            return false
        #endif
    }
    private func isReachable(flags: SCNetworkReachabilityFlags) -> Bool {
        return flags.contains(.Reachable)
    }
    private func isConnectionRequired(flags: SCNetworkReachabilityFlags) -> Bool {
        return flags.contains(.ConnectionRequired)
    }
    private func isInterventionRequired(flags: SCNetworkReachabilityFlags) -> Bool {
        return flags.contains(.InterventionRequired)
    }
    private func isConnectionOnTraffic(flags: SCNetworkReachabilityFlags) -> Bool {
        return flags.contains(.ConnectionOnTraffic)
    }
    private func isConnectionOnDemand(flags: SCNetworkReachabilityFlags) -> Bool {
        return flags.contains(.ConnectionOnDemand)
    }
    func isConnectionOnTrafficOrDemand(flags: SCNetworkReachabilityFlags) -> Bool {
        return !flags.intersect([.ConnectionOnTraffic, .ConnectionOnDemand]).isEmpty
    }
    private func isTransientConnection(flags: SCNetworkReachabilityFlags) -> Bool {
        return flags.contains(.TransientConnection)
    }
    private func isLocalAddress(flags: SCNetworkReachabilityFlags) -> Bool {
        return flags.contains(.IsLocalAddress)
    }
    private func isDirect(flags: SCNetworkReachabilityFlags) -> Bool {
        return flags.contains(.IsDirect)
    }
    private func isConnectionRequiredOrTransient(flags: SCNetworkReachabilityFlags) -> Bool {
        let testcase:SCNetworkReachabilityFlags = [.ConnectionRequired, .TransientConnection]
        return flags.intersect(testcase) == testcase
    }

    private var reachabilityFlags: SCNetworkReachabilityFlags {

        guard let reachabilityRef = reachabilityRef else { return SCNetworkReachabilityFlags() }

        var flags = SCNetworkReachabilityFlags()
        let gotFlags = withUnsafeMutablePointer(&flags) {
            SCNetworkReachabilityGetFlags(reachabilityRef, UnsafeMutablePointer($0))
        }

        if gotFlags {
            return flags
        } else {
            return SCNetworkReachabilityFlags()
        }
    }

    override public var description: String {

        var W: String
        if isRunningOnDevice {
            W = isOnWWAN(reachabilityFlags) ? "W" : "-"
        } else {
            W = "X"
        }
        let R = isReachable(reachabilityFlags) ? "R" : "-"
        let c = isConnectionRequired(reachabilityFlags) ? "c" : "-"
        let t = isTransientConnection(reachabilityFlags) ? "t" : "-"
        let i = isInterventionRequired(reachabilityFlags) ? "i" : "-"
        let C = isConnectionOnTraffic(reachabilityFlags) ? "C" : "-"
        let D = isConnectionOnDemand(reachabilityFlags) ? "D" : "-"
        let l = isLocalAddress(reachabilityFlags) ? "l" : "-"
        let d = isDirect(reachabilityFlags) ? "d" : "-"

        return "\(W)\(R) \(c)\(t)\(i)\(C)\(D)\(l)\(d)"
    }

    deinit {
        stopNotifier()

        reachabilityRef = nil
        whenReachable = nil
        whenUnreachable = nil
    }
}

@ Xitcod13 To działałoby z siecią 4G. Biorąc to pod uwagę, NIE zaleca się testowania inspekcji wstępnej. Obsługiwany jest wyjątek zgłoszony podczas próby połączenia zamiast użycia przypadku testowego Reachability.swift.
cmeadows


Reachabilty.swift ma problemy ze Swift 3
Famic Tech

Działa dobrze z Swift 3, wystarczy zmienić let reachability: Reachability = try Reachability.reachabilityForInternetConnection()nalet reachability: Reachability = try Reachability()!
davidethell

7

Chociaż nie odpowiada bezpośrednio na twoje pytanie, chciałbym wspomnieć, że Apple niedawno miał tę rozmowę:

https://developer.apple.com/videos/play/wwdc2018/714/

Około 09:55 mówi o robieniu rzeczy, o które pytasz:

  1. Sprawdź połączenie
  2. Jeśli połączenie -> Zrób coś
  3. Jeśli nie ma połączenia -> Zrób coś innego (poczekaj, spróbuj ponownie?)

Ma to jednak kilka pułapek:

  • Co jeśli w kroku 2 jest napisane, że ma połączenie, ale 0,5 sekundy później nie ma?
  • Co jeśli użytkownik stoi za serwerem proxy
  • Wreszcie, co jeśli niektóre odpowiedzi tutaj nie mogą ustalić prawidłowej łączności? (Jestem pewien, że jeśli szybko zmienisz połączenie, wejdziesz do Wi-Fi i je wyłączysz (tylko komplikujesz), prawie nigdy nie będzie w stanie poprawnie ustalić, czy mam połączenie, czy nie.
  • Cytat z filmu: „Nie ma sposobu, aby zagwarantować, czy przyszła operacja się powiedzie, czy nie”

Następujące punkty to niektóre najlepsze praktyki według Apple:

Zgodnie z rozmową nie powinno być żadnego powodu, by sprawdzać, czy masz połączenie internetowe, czy nie, ponieważ może to nie być dokładne w momencie wysyłania żądania na serwer .


2

Stworzyłem własne rozwiązanie przy użyciu NSTimer i Alamofire:

import Alamofire

public class ConnectionHelper: NSObject {
    var request: Alamofire.Request?

    func isInternetConnected(completionHandler: Bool -> Void) {
        NSTimer.scheduledTimerWithTimeInterval(5.0, target: self, selector: "requestTimeout", userInfo: nil, repeats: false)

        request = Alamofire
            .request(
                Method.HEAD,
                "http://www.testurl.com"
            )
            .response { response in
                if response.3?.code == -999 {
                    completionHandler(
                        false
                    )
                } else {
                    completionHandler(
                        true
                    )
                }
        }
    }

    func requestTimeout() {
        request!.cancel()
    }
}

NSTimer jest używany jako limit czasu i został użyty z powodu niewiarygodnych wyników przy użyciu limitu czasu Alamofire. Żądanie powinno zostać przesłane na adres URL, który jest zaufany, aby był niezawodny, na przykład na własny serwer lub serwer, na którym znajdują się usługi, na których można polegać.

Po wygaśnięciu timera żądanie jest anulowane, a wyniki są zwracane za pomocą procedury obsługi zakończenia.

Stosowanie:

ConnectionHelper().isInternetConnected() { internetConnected in
    if internetConnected {
        // Connected
    } else {
        // Not connected
    }
}

1
Co się stanie, jeśli serwer strony nie będzie działał?
TechBee

Wtedy requestTimeout()byłoby nazwać po określony limit czasu został osiągnięty
Mark Tickner

Dzięki Mark! Twoje podejście powinno być ogólne !!
TechBee

1
W jaki sposób? Strona, która jest używana? Pomysł polegałby na tym, że używana strona jest tą, od której zależy Twoja aplikacja
Mark Tickner

Prawdopodobnie nie jest to dobry pomysł na nawiązanie połączenia sieciowego i sprawdzenie, czy wróci z odpowiedzią, czy nie. Jest po prostu zbyt wiele, co jeśli pytania
GoodSp33d 10.04.16

2

Jeśli używasz Alamofire, możesz zrobić coś takiego:

let configuration = NSURLSessionConfiguration.defaultSessionConfiguration()
configuration.timeoutIntervalForRequest = 15 //Set timeouts in sec
configuration.timeoutIntervalForResource = 15

let alamoFireManager = Alamofire.Manager(configuration:configuration)
alamoFireManager?.request(.GET, "https://yourURL.com", parameters: headers, encoding: .URL)
                     .validate()
                              .responseJSON { response in

                                if let error = response.result.error {
                                   switch error.code{
                                    case -1001:
                                        print("Slow connection")
                                        return
                                    case -1009:
                                        print("No Connection!")
                                        return
                                    default: break
                                    }
                                }

1

tutaj moje rozwiązanie dla swift 2.3 z lib ( Reachability.swift )

Wejdź do swojego Podfilei dodaj:

pod 'ReachabilitySwift', '~> 2.4' // swift 2.3

Następnie do terminal:

pod install

Następnie utwórz nowy plik ReachabilityManageri dodaj kod poniżej:

import Foundation
import ReachabilitySwift

enum ReachabilityManagerType {
    case Wifi
    case Cellular
    case None
}

class ReachabilityManager {
    static let sharedInstance = ReachabilityManager()

    private var reachability: Reachability!
    private var reachabilityManagerType: ReachabilityManagerType = .None


    private init() {
        do {
            self.reachability = try Reachability.reachabilityForInternetConnection()
        } catch {
            print("Unable to create Reachability")
            return
        }

        NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(ReachabilityManager.reachabilityChanged(_:)),name: ReachabilityChangedNotification,object: self.reachability)
        do{
            try self.reachability.startNotifier()
        }catch{
            print("could not start reachability notifier")
        }
    }

    @objc private func reachabilityChanged(note: NSNotification) {

        let reachability = note.object as! Reachability

        if reachability.isReachable() {
            if reachability.isReachableViaWiFi() {
                self.reachabilityManagerType = .Wifi
            } else {
                self.reachabilityManagerType = .Cellular
            }
        } else {
            self.reachabilityManagerType = .None
        }
    }
}

extension ReachabilityManager {

    func isConnectedToNetwork() -> Bool {
        return reachabilityManagerType != .None
    }

}

Jak tego użyć:

idź do AppDelegate.swifti dodaj poniższy kod:

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
     ReachabilityManager.sharedInstance
}

Następnie, jeśli chcesz sprawdzić, czy urządzenie jest podłączone do Internetu:

if ReachabilityManager.sharedInstance.isConnectedToNetwork() {
   // Connected
} else {
  // Not connected
}

1

Chociaż nie może bezpośrednio określić, czy telefon jest podłączony do sieci, najprostszym (najczystszym?) Rozwiązaniem byłoby „pingowanie” Google'a lub innego serwera (co nie jest możliwe, chyba że telefon jest podłączony do sieci ):

private var urlSession:URLSession = {
    var newConfiguration:URLSessionConfiguration = .default
    newConfiguration.waitsForConnectivity = false
    newConfiguration.allowsCellularAccess = true
    return URLSession(configuration: newConfiguration)
}()

public func canReachGoogle() -> Bool
{
    let url = URL(string: "https://8.8.8.8")
    let semaphore = DispatchSemaphore(value: 0)
    var success = false
    let task = urlSession.dataTask(with: url!)
    { data, response, error in
        if error != nil
        {
            success = false
        }
        else
        {
            success = true
        }
        semaphore.signal()
    }

    task.resume()
    semaphore.wait()

    return success
}

Jeśli obawiasz się, że serwer może być wyłączony lub może zablokować twoje IP, zawsze możesz pingować wiele serwerów w podobny sposób i zwrócić, czy któryś z nich jest osiągalny. Lub niech ktoś skonfiguruje serwer dedykowany tylko w tym celu.


1

Szybki 5

import SystemConfiguration    

protocol Utilities {}
extension NSObject: Utilities {
    enum ReachabilityStatus {
        case notReachable
        case reachableViaWWAN
        case reachableViaWiFi
    }

    var currentReachabilityStatus: ReachabilityStatus {

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

        var flags: SCNetworkReachabilityFlags = []
        if !SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags) {
            return .notReachable
        }

        if flags.contains(.reachable) == false {
            // The target host is not reachable.
            return .notReachable
        }
        else if flags.contains(.isWWAN) == true {
            // WWAN connections are OK if the calling application is using the CFNetwork APIs.
            return .reachableViaWWAN
        }
        else if flags.contains(.connectionRequired) == false {
            // If the target host is reachable and no connection is required then we'll assume that you're on Wi-Fi...
            return .reachableViaWiFi
        }
        else if (flags.contains(.connectionOnDemand) == true || flags.contains(.connectionOnTraffic) == true) && flags.contains(.interventionRequired) == false {
            // The connection is on-demand (or on-traffic) if the calling application is using the CFSocketStream or higher APIs and no [user] intervention is needed
            return .reachableViaWiFi
        }
        else {
            return .notReachable
        }
    }
}

W dowolnej metodzie użyj poniższego warunku

if currentReachabilityStatus == .notReachable {
    // Network Unavailable
 } else {
    // Network Available
 }

0

Za pomocą poniższego kodu możesz sprawdzić połączenie internetowe zarówno dla sieci komórkowej, jak i dla Wi-Fi. język - Swift 3.0

import UIKit
import Foundation
import SystemConfiguration

class NetworkConnection: UIViewController {

  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(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) {
        SCNetworkReachabilityCreateWithAddress(nil, $0)
      }
    }) else {
      return false
    }

    var flags: SCNetworkReachabilityFlags = SCNetworkReachabilityFlags(rawValue: 0)
    if SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags) == false {
      return false
    }
    let isReachable = (flags.rawValue & UInt32(kSCNetworkFlagsReachable)) != 0
    let needsConnection = (flags.rawValue & UInt32(kSCNetworkFlagsConnectionRequired)) != 0
    return (isReachable && !needsConnection)
  }

  class func checkConnection(sender:UIViewController){
    if NetworkConnection.isConnectedToNetwork() == true {
      print("Connected to the internet")
      //  Do something
    } else {
      print("No internet connection")
      let alertController = UIAlertController(title: "No Internet Available", message: "", preferredStyle: UIAlertControllerStyle.alert)
      let okAction = UIAlertAction(title: "Ok", style: UIAlertActionStyle.default){(result:UIAlertAction) -> Void in
        return
      }
      alertController.addAction(okAction)
      sender.present(alertController, animated: true, completion: nil)
      //  Do something
    }
  }

}

0

W przypadku swift 3 nie mogłem użyć tylko osiągalności z rozwiązań RAJAMOHAN-S, ponieważ zwraca „prawda”, jeśli jest WiFi, ale nie ma Internetu. Dlatego zaimplementowałem drugą weryfikację za pomocą klasy URLSession i modułu obsługi zakończenia.

Oto cała klasa.

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(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 = SCNetworkReachabilityFlags(rawValue: 0)
if SCNetworkReachabilityGetFlags(defaultRouteReachability!, &flags) == false {
  return false
}

// Working for Cellular and WIFI
let isReachable = (flags.rawValue & UInt32(kSCNetworkFlagsReachable)) != 0
let needsConnection = (flags.rawValue & UInt32(kSCNetworkFlagsConnectionRequired)) != 0
let ret = (isReachable && !needsConnection)

return ret
}



class func isInternetAvailable(webSiteToPing: String?, completionHandler: @escaping (Bool) -> Void) {

// 1. Check the WiFi Connection
guard isConnectedToNetwork() else {
  completionHandler(false)
  return
}

// 2. Check the Internet Connection
var webAddress = "https://www.google.com" // Default Web Site
if let _ = webSiteToPing {
  webAddress = webSiteToPing!
}

guard let url = URL(string: webAddress) else {
  completionHandler(false)
  print("could not create url from: \(webAddress)")
  return
}

let urlRequest = URLRequest(url: url)
let session = URLSession.shared
let task = session.dataTask(with: urlRequest, completionHandler: { (data, response, error) in
  if error != nil || response == nil {
    completionHandler(false)
  } else {
    completionHandler(true)
  }
})

  task.resume()
}
}

I nazywasz to tak, na przykład:

Reachability.isInternetAvailable(webSiteToPing: nil) { (isInternetAvailable) in
  guard isInternetAvailable else {
    // Inform user for example
    return
  }

  // Do some action if there is Internet
}

0

To jest moja wersja. Zasadniczo nie przynosi niczego nowego. Związałem to z UIDevice.

import UIKit
import SystemConfiguration

extension UIDevice {

    open class var isConnectedToNetwork: Bool {
        get {
            var zeroAddress = sockaddr_in()
            zeroAddress.sin_len = UInt8(MemoryLayout.size(ofValue: zeroAddress))
            zeroAddress.sin_family = sa_family_t(AF_INET)

            guard
                let defaultRouteReachability: SCNetworkReachability = withUnsafePointer(to: &zeroAddress, {
                    $0.withMemoryRebound(to: sockaddr.self, capacity: 1) {
                        SCNetworkReachabilityCreateWithAddress(nil, $0)
                    }
                }),
                var flags: SCNetworkReachabilityFlags = SCNetworkReachabilityFlags() as SCNetworkReachabilityFlags?,
                SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags)
                else { return false }

            return flags.contains(.reachable) && !flags.contains(.connectionRequired)
        }
    }

}

print("Network status availability: " + ( UIDevice.isConnectedToNetwork ? "true" : "false" ))

0
struct Connectivity {
        static let sharedInstance = NetworkReachabilityManager()!
        static var isConnectedToInternet:Bool {
            return self.sharedInstance.isReachable
        }
    }

Nazwij to teraz

if Connectivity.isConnectedToInternet{
            call_your_methods_here()
        }else{
            show_alert_for_noInternet()
        }
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.