ตรวจสอบความพร้อมการเชื่อมต่ออินเทอร์เน็ตใน Swift


107

มีวิธีตรวจสอบว่าการเชื่อมต่ออินเทอร์เน็ตใช้งานได้โดยใช้ Swift หรือไม่?

ฉันรู้ว่ามีไลบรารีของบุคคลที่สามจำนวนมากที่จะทำสิ่งนี้ แต่ทั้งหมดนี้เขียนใน Objective-C ฉันกำลังมองหาทางเลือกอื่นของ Swift


5
ประโยชน์มหาศาลอย่างหนึ่งของ Swift คือการทำงานร่วมกับ Objective-C (และไลบรารีประเภทนี้) ได้เป็นอย่างดี
user2864740

แน่นอน. คุณประสบปัญหาอะไรในการใช้ไลบรารีที่มีอยู่ มันค่อนข้างง่ายที่จะใช้ไลบรารี Objective C จาก Swift และจะพิสูจน์ได้ยากมากสำหรับคุณที่จะเขียนแอพประเภทใดก็ได้ใน Swift หากคุณไม่สามารถทำได้
Matt Gibson

1
@MattGibson เกือบทุกอย่างที่คุณทำได้ใน ObjC สามารถทำได้ใน Swift อย่างง่ายดาย จริงอยู่ว่าในกรณีนี้จะมีบรรทัดพิเศษเล็กน้อย แต่ก็ยังห่างไกลจาก "ยากมาก"
Byron Coetsee

@ByronCoetsee ฉันรวมถึงการใช้ไลบรารีเช่น AppKit เป็นต้น - ประเด็นของฉันคือคุณจะต้องรู้วิธีโต้ตอบกับไลบรารี Objective C เพื่อเขียนสิ่งที่มีประโยชน์ใน Swift
Matt Gibson

ดูคำตอบของ alamofire - stackoverflow.com/a/46562290/7576100
Jack

คำตอบ:


228

ดังที่ได้กล่าวไว้ในความคิดเห็นแม้ว่าจะสามารถใช้ไลบรารี Objective-C ใน Swift ได้ แต่ฉันก็ต้องการโซลูชัน Swift ที่บริสุทธิ์ยิ่งขึ้น คลาส Apple Reachability ที่มีอยู่และไลบรารีบุคคลที่สามอื่น ๆ ดูเหมือนจะซับซ้อนเกินกว่าที่ฉันจะแปลเป็น Swift ฉัน Googled เพิ่มเติมและฉันเจอบทความนี้ซึ่งแสดงวิธีง่ายๆในการตรวจสอบความพร้อมใช้งานของเครือข่าย ฉันตั้งใจจะแปลสิ่งนี้เป็น Swift ฉันประสบปัญหามากมายแต่ต้องขอบคุณMartin Rจาก StackOverflow ฉันสามารถแก้ไขปัญหาเหล่านี้ได้และในที่สุดก็ได้โซลูชันที่ใช้งานได้ใน Swift นี่คือรหัส

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
    }

}

สำหรับ 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)
    }
}

ใช้ได้กับทั้งการเชื่อมต่อ 3G และ WiFi ฉันได้อัปโหลดไปยังGitHubด้วยตัวอย่างการทำงาน


7
ขอบคุณสำหรับการตอบสนองที่รวดเร็ว (ไม่มีการเล่นสำนวน) MIT หรือ Apache จะเหมาะ - ขอบคุณ!
Andrew Ebling

4
เสร็จแล้ว เปลี่ยนเป็น MIT
Isuru

11
ฉันพบปัญหาอื่นหากเปิด 3Gแต่ฉันไม่มีความจุข้อมูลเพิ่มขึ้นแล้วisConnectedToNetworkจะส่งคืนจริงแต่ฉันไม่สามารถเรียกใช้บริการเว็บของฉันได้
János

11
ดังที่ @Isuru กล่าวว่านี่เป็นไปตามstackoverflow.com/a/25623647/1187415ซึ่งตอนนี้ได้รับการอัปเดตสำหรับ Swift 2 แล้ว
Martin R

2
@ János: การตั้งค่าการเรียกกลับการแจ้งเตือนอยู่ในขณะนี้เป็นไปได้ด้วยสวิฟท์ 2 ดูปรับปรุงคำตอบstackoverflow.com/a/27142665/1187415
Martin R

16

ฉันให้วิธีที่ดีกว่า ...

คุณต้องสร้างคลาสด้วยรหัสนี้

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

จากนั้นคุณสามารถตรวจสอบการเชื่อมต่ออินเทอร์เน็ตได้ทุกที่ในโครงการของคุณโดยใช้รหัสนี้:

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

ง่ายมาก!

* วิธีนี้ยึดตามคำตอบของวิกรมพจน์!


15
โปรดทราบว่าคุณไม่ควรใช้วิธีนี้กับวิธีที่ใช้ข้างต้น ในแอปพลิเคชันที่ต้องการการเชื่อมต่ออย่างต่อเนื่องการตรวจสอบการตอบสนองเช่นวิธีนี้จะส่งผลให้แอปหยุดทำงานในสถานการณ์ที่การเชื่อมต่ออินเทอร์เน็ตของคุณไม่ดี (เช่นบน Edge / GPRS) โปรดอย่าใช้วิธีนี้ !!
Imran Ahmed

7
วิธีที่ไม่ดี 1) ต้องการการเข้าชมเซิร์ฟเวอร์เป็นพิเศษ 2) google.comสามารถลงได้
Vijay Singh Rana

2
1. ใช่วิธีนี้ต้องการการเข้าชมเซิร์ฟเวอร์เป็นพิเศษทุกครั้ง แต่ให้การรับประกัน 100% ว่าอินเทอร์เน็ตพร้อมใช้งาน ... มีบางครั้งที่อุปกรณ์เชื่อมต่อกับเครือข่าย wifi แต่ไม่สามารถเชื่อมต่ออินเทอร์เน็ตได้! ในสถานการณ์เช่นนี้วิธีนี้กำหนดว่าจะขาดการเข้าถึงอินเทอร์เน็ต ... วิธีอื่น - ไม่! 2. คุณสามารถใช้เซิร์ฟเวอร์ของคุณเองแทน google.com ... เดิมหมายถึง ...
Dmitry

1
ทางออกที่ไม่ดีนักฆ่าการเชื่อมต่อ
gokhanakkurt

2
gokhanakkurt โปรดแนะนำวิธีแก้ปัญหาอื่นที่ช่วยให้มั่นใจได้ว่าอินเทอร์เน็ตทำงานได้ 100%
Dmitry

15

สำหรับ Swift 3.1 (iOS 10.1)

หากคุณต้องการสร้างความแตกต่างระหว่างประเภทเครือข่าย (เช่น WiFi หรือ WWAN):

คุณสามารถใช้ได้:

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

นี่คือ Reachability-Class ทั้งหมดที่แยกความแตกต่างระหว่างประเภทเครือข่าย:

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

ทำงานได้ดีตั้งแต่วันที่ 3 ธันวาคม 2016, iOS 10 และ swift 3.1 ขอบคุณ!
โจอี้

สวัสดีถ้าเราต้องการแยกความแตกต่างของการเชื่อมต่อ Wifi / 3G / Mobile-Data / 4G สำหรับวิธีที่เราสามารถระบุได้

6

เนื่องจาก sendSynchronousRequest เลิกใช้งานแล้วฉันจึงลองทำ แต่ 'return Status' ถูกเรียกก่อนที่การตอบกลับจะเสร็จสิ้น

คำตอบนี้ใช้ได้ดีแม้ว่า ตรวจสอบการเชื่อมต่ออินเทอร์เน็ตด้วย Swift

นี่คือสิ่งที่ฉันพยายามต่อไป:

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

ฉันชอบและใช้โซลูชันของคุณ แต่ฉันเพิ่มมันรวมกับคำตอบนี้: stackoverflow.com/a/34591379 aka ฉันเพิ่มสัญญาณแล้ว .. ดังนั้นฉันรอให้งานเสร็จ
Bjqn

6

SWIFT 3: ตรวจสอบการเชื่อมต่อwifiและอินเทอร์เน็ต :

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

การใช้งาน:

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

2
public func isConnectedToNetwork() {...}ควรเปลี่ยนเป็นclass func isConnectedToNetwork{...}สำหรับกรณีการใช้งานของคุณ
keverly

4

คุณยังสามารถใช้คำตอบด้านล่าง

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

ขอบคุณ! ฉันได้รับการแก้ไขอัตโนมัติจากการตอบสนองเป็น NSHTTPURLResponse? เพื่อตอบสนอง! NSHTTPURLR การตอบสนอง? ใน Swift 1.2
Francis Jervis

1

SWIFT 3:ตรวจสอบการเชื่อมต่อ 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()
}

นี่ไม่ใช่วิธีที่ต้องการ จะเกิดอะไรขึ้นหากในอนาคตลิงก์ของเว็บที่ให้ไว้หยุดตอบสนองหรือหยุดทำงาน ฉันอยากจะแนะนำให้ใช้กรอบ Apple SystemConfiguration สำหรับสิ่งนี้ ดูคำตอบด้านบน
อับดุลยา

1

สำหรับ Swift 5:

import Network
let monitor = NWPathMonitor()

func checkInterwebs() -> Bool {
    var status = false
    monitor.pathUpdateHandler = { path in
        if path.status == .satisfied {
            status = true  // online
        }
    }
    return status
}

1

สวิฟต์ 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)
}

0

ฉันพบคำตอบที่ดีที่สุดแล้วและตรวจสอบสถานะการเชื่อมต่ออินเทอร์เน็ตทุกครั้ง

ในการเริ่มต้นขั้นแรกให้เพิ่มการนำเข้าสำหรับกรอบเครือข่าย:

import Network

จากนั้นสร้างอินสแตนซ์ของ NWPathMonitor

let monitor = NWPathMonitor()

เพื่อลองสิ่งนี้

 monitor.pathUpdateHandler = { path in
    if path.status == .satisfied {
      print("We're connected!")
    } else {
      print("No connection.")
    }
    print(path.isExpensive)
 }

โปรดจำไว้ว่าการปิดนั้นจะถูกเรียกทุกครั้งที่สถานะการเชื่อมต่อเปลี่ยนไป

 let queue = DispatchQueue(label: "Monitor")
 monitor.start(queue: queue)

ฉันใช้สิ่งนี้ใน View controller ได้อย่างไร

class testViewController: UIViewController {

@IBOutlet weak var status: UILabel!
let monitor = NWPathMonitor()

override func viewDidLoad() {
    super.viewDidLoad()
    
    let queue = DispatchQueue(label: "Monitor")
    monitor.start(queue: queue)
    _ = NWPathMonitor(requiredInterfaceType: .cellular)
    
    monitor.pathUpdateHandler = { path in
        if path.status == .satisfied {
            print("We're connected!")
            DispatchQueue.main.async {
                self.status.text = "We're connected!"
            }
            
        } else {
            print("No connection.")
            DispatchQueue.main.async {
                self.status.text = "No connection."
            }  
        }
    }
 }
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.