Periksa ketersediaan koneksi internet di Swift

107

Adakah cara untuk memeriksa apakah koneksi internet tersedia menggunakan Swift?

Saya tahu ada banyak perpustakaan pihak ketiga untuk melakukan ini, tetapi semuanya ditulis dalam Objective-C. Saya mencari alternatif Swift.

Isuru
sumber
5
Salah satu manfaat besar Swift adalah ia terintegrasi dengan baik dengan Objective-C (dan pustaka semacam itu).
pengguna2864740
Memang. Masalah apa yang Anda alami saat menggunakan salah satu pustaka yang ada? Sangat mudah untuk menggunakan pustaka Objective C dari Swift, dan akan terbukti sangat sulit bagi Anda untuk menulis aplikasi apa pun di Swift jika Anda tidak dapat melakukannya.
Matt Gibson
1
@MattGibson hampir semua yang dapat Anda lakukan di ObjC dapat dilakukan di Swift dengan relatif mudah. Memang, dalam hal ini akan ada beberapa baris tambahan tetapi masih jauh dari "sangat sulit"
Byron Coetsee
@ByronCoetsee Saya termasuk menggunakan perpustakaan seperti AppKit, dll — maksud saya adalah bahwa Anda harus tahu bagaimana berinteraksi dengan perpustakaan Objective C untuk menulis sesuatu yang berguna di Swift.
Matt Gibson
Lihat jawaban alamofire - stackoverflow.com/a/46562290/7576100
Jack

Jawaban:

228

Seperti yang disebutkan dalam komentar, meskipun dimungkinkan untuk menggunakan pustaka Objective-C di Swift, saya menginginkan solusi Swift yang lebih murni. Kelas Apple Reachability yang sudah ada dan pustaka pihak ketiga lainnya tampaknya terlalu rumit untuk saya terjemahkan ke Swift. Saya mencari di Google lagi dan saya menemukan artikel ini yang menunjukkan metode sederhana untuk memeriksa ketersediaan jaringan. Saya mulai menerjemahkan ini ke Swift. Saya mengalami banyak halangan tetapi berkat Martin R dari StackOverflow, saya berhasil menyelesaikannya dan akhirnya mendapatkan solusi yang bisa diterapkan di Swift. Ini kodenya.

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
    }

}

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

Ini berfungsi untuk koneksi 3G dan WiFi. Saya juga mengunggahnya ke GitHub saya dengan contoh yang berfungsi.

Isuru
sumber
7
Terima kasih atas tanggapan yang cepat (tidak ada permainan kata-kata). MIT atau Apache akan ideal - terima kasih!
Andrew Ebling
4
Selesai. Berubah menjadi MIT.
Isuru
11
Saya menemukan masalah lain, jika 3G diaktifkan tetapi saya tidak memiliki kapasitas data lagi, lalu isConnectedToNetworkmengembalikan true, tetapi saya tidak dapat menghubungi layanan web saya
János
11
Seperti yang dikatakan @Isuru, ini didasarkan pada stackoverflow.com/a/25623647/1187415 , yang sekarang telah diperbarui untuk Swift 2.
Martin R
2
@ János: Menyetel panggilan balik pemberitahuan sekarang dapat dilakukan dengan Swift 2, lihat jawaban yang diperbarui stackoverflow.com/a/27142665/1187415 .
Martin R
16

Saya memberi Anda cara yang lebih baik ...

Anda harus membuat kelas dengan kode ini

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

Dan kemudian Anda dapat memeriksa koneksi internet di mana saja dalam proyek Anda menggunakan kode ini:

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

Sangat mudah!

* Cara ini berdasarkan jawaban Vikram Pote!

Dmitry
sumber
15
Perlu diketahui bahwa Anda tidak boleh menggunakan metode ini di atas metode yang digunakan di atas. Dalam aplikasi yang membutuhkan konektivitas konstan, pemeriksaan respons seperti metode ini akan mengakibatkan aplikasi terhenti dalam situasi di mana konektivitas internet Anda buruk (yaitu di Edge / GPRS). Tolong jangan gunakan solusi ini !!
Imran Ahmed
7
Cara buruk 1) Perlu hit ekstra ke server setiap waktu 2) google.com juga bisa turun
Vijay Singh Rana
2
1. Ya, cara ini membutuhkan hit ekstra ke server setiap saat, tetapi memberikan jaminan 100% bahwa Internet tersedia ... ada kalanya perangkat terhubung ke jaringan wifi tetapi tidak menyediakan akses internet! Dalam situasi ini, cara ini menentukan kurangnya akses ke Internet ... cara lain - tidak! 2. Anda dapat menggunakan server Anda sendiri, bukan google.com ... Ini awalnya dimaksudkan ...
Dmitry
1
solusi yang buruk, pembunuh koneksi.
gokhanakkurt
2
gokhanakkurt, tolong, sarankan solusi lain yang memastikan bahwa Internet bekerja pada 100%
Dmitry
15

Untuk Swift 3.1 (iOS 10.1)

Jika Anda ingin membuat perbedaan antara tipe jaringan (yaitu WiFi atau WWAN):

Kamu bisa memakai:

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

Berikut adalah seluruh Reachability-Class yang membedakan antara tipe jaringan:

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
sumber
berfungsi dengan baik pada 3 Des 2016, iOS 10 dan swift 3.1, terima kasih!
joey
Halo, jika kami ingin membedakan koneksi Wifi / 3G / Mobile-Data / 4G untuk itu bagaimana kami dapat mengidentifikasi.
6

Karena sendSynchronousRequest sudah tidak digunakan lagi, saya mencoba ini tetapi 'Status kembali' dipanggil sebelum tanggapan selesai.

Jawaban ini bekerja dengan baik, Periksa koneksi internet dengan Swift

Inilah yang saya coba:

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
sumber
Saya menyukai dan menggunakan solusi Anda. Tetapi saya menambahkan kombinasi itu dengan jawaban ini: stackoverflow.com/a/34591379 aka. saya menambahkan semaphore .. Jadi saya menunggu tugas selesai.
Bjqn
6

SWIFT 3: Memeriksa koneksi wifi dan internet :

import Foundation
import SystemConfiguration

public class Reachability {
    public func isConnectedToNetwork() -> Bool {
        var zeroAddress = sockaddr_in()
        zeroAddress.sin_len = UInt8(MemoryLayout<sockaddr_in>.size)
        zeroAddress.sin_family = sa_family_t(AF_INET)

        guard let defaultRouteReachability = withUnsafePointer(to: &zeroAddress, {
            $0.withMemoryRebound(to: sockaddr.self, capacity: 1) {
                SCNetworkReachabilityCreateWithAddress(nil, $0)
            }
        }) else {
            return false
        }

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

        let isReachable = flags.contains(.reachable)
        let needsConnection = flags.contains(.connectionRequired)

        return (isReachable && !needsConnection)
    }
}

PEMAKAIAN:

if Reachability.isConnectedToNetwork() == true {
    print("Connected to the internet")
    //  Do something
} else {
    print("No internet connection")
    //  Do something
}
Gilad Brunfman
sumber
2
public func isConnectedToNetwork() {...}harus diubah menjadi class func isConnectedToNetwork{...}untuk kasus penggunaan Anda.
tajam
4

Anda juga dapat menggunakan jawaban di bawah ini.

    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
sumber
Terima kasih! Saya mendapat koreksi otomatis dari tanggapan sebagai NSHTTPURLResponse? untuk menanggapi sebagai! NSHTTPURLResponse? di Swift 1.2.
Francis Jervis
1

SWIFT 3: Periksa koneksi 3G & 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
sumber
Ini bukan cara yang disukai. Bagaimana jika di beberapa titik di masa depan tautan web yang disediakan berhenti untuk merespons atau turun. Saya akan merekomendasikan untuk menggunakan kerangka kerja Konfigurasi Sistem Apple untuk ini. Lihat jawaban di atas.
Abdul Yasin
1

Untuk 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
sumber
1

Cepat 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
sumber