Kiểm tra tính khả dụng của kết nối Internet trong Swift


107

Có cách nào để kiểm tra xem kết nối internet có khả dụng bằng Swift không?

Tôi biết có rất nhiều thư viện của bên thứ ba để thực hiện việc này nhưng chúng đều được viết bằng Objective-C. Tôi đang tìm kiếm một sự thay thế Swift.


5
Một trong những lợi ích to lớn của Swift là nó tích hợp tốt với Objective-C (và các thư viện như vậy).
user2864740

Thật. Bạn đang gặp vấn đề gì khi sử dụng một trong các thư viện hiện có? Việc sử dụng thư viện Objective C từ Swift khá đơn giản và sẽ rất khó để bạn viết bất kỳ loại ứng dụng nào bằng Swift nếu bạn không thể làm được.
Matt Gibson

1
@MattGibson hầu hết mọi thứ bạn có thể làm trong ObjC đều có thể được thực hiện bằng Swift một cách tương đối dễ dàng. Cấp, trong trường hợp này sẽ có một vài dòng phụ trợ nhưng vẫn còn xa mới "vô cùng khó khăn"
Byron Coetsee

@ByronCoetsee Tôi đã sử dụng các thư viện như AppKit, v.v. — quan điểm của tôi là bạn sẽ cần biết cách tương tác với các thư viện Objective C để viết bất kỳ thứ gì hữu ích trong Swift.
Matt Gibson

Xem câu trả lời của alamofire - stackoverflow.com/a/46562290/7576100
Jack

Câu trả lời:


228

Như đã đề cập trong các nhận xét, mặc dù có thể sử dụng các thư viện Objective-C trong Swift, nhưng tôi muốn có một giải pháp Swift thuần túy hơn. Lớp Apple Reachability hiện có và các thư viện bên thứ ba khác dường như quá phức tạp đối với tôi để dịch sang Swift. Tôi đã tìm kiếm thêm trên Google và xem qua bài viết này cho thấy một phương pháp đơn giản để kiểm tra tính khả dụng của mạng. Tôi bắt đầu dịch nó sang Swift. Tôi nhấn nhiều snags nhưng nhờ Martin R từ StackOverflow, tôi quản lý để giải quyết chúng và cuối cùng là có được một giải pháp khả thi trong Swift. Đây là mã.

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
    }

}

Đối với 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)
    }
}

Điều này hoạt động cho cả kết nối 3G và WiFi. Tôi cũng đã tải nó lên GitHub của mình với một ví dụ hoạt động.


7
Cảm ơn vì phản hồi nhanh chóng (không có ý định chơi chữ). MIT hoặc Apache sẽ là lý tưởng - cảm ơn!
Andrew Ebling

4
Làm xong. Đã đổi nó thành MIT.
Isuru

11
Tôi phát hiện thấy một vấn đề khác, nếu 3G được bật nhưng tôi không còn dung lượng dữ liệu nữa thì isConnectedToNetworktrả về true, nhưng tôi không thể gọi dịch vụ web của mình
János

11
Như @Isuru nói, điều này được dựa trên stackoverflow.com/a/25623647/1187415 , mà hiện đã được cập nhật cho Swift 2.
Martin R

2
@ János: Hiện có thể đặt lệnh gọi lại thông báo với Swift 2, hãy xem câu trả lời cập nhật stackoverflow.com/a/27142665/1187415 .
Martin R

16

Tôi cho bạn cách tốt hơn ...

Bạn phải tạo một lớp với mã này

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

Và sau đó, bạn có thể kiểm tra kết nối internet ở bất kỳ đâu trong dự án của mình bằng mã này:

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

Rất dễ!

* Cách này dựa trên câu trả lời của Vikram Pote!


15
Xin lưu ý rằng bạn không nên sử dụng phương pháp này thay vì phương pháp được sử dụng ở trên. Trong các ứng dụng yêu cầu kết nối liên tục, kiểm tra phản hồi như phương pháp này sẽ dẫn đến việc ứng dụng bị treo trong các trường hợp kết nối internet của bạn kém (tức là trên Edge / GPRS). Vui lòng không sử dụng giải pháp này !!
Imran Ahmed

7
Xấu cách 1) Cần thêm hit gian máy chủ Évry 2) google.com cũng có thể là xuống
Vijay Singh Rana

2
1. Có, cách này cần thêm lượt truy cập vào máy chủ mỗi lần, nhưng nó đảm bảo 100% rằng có Internet ... có những lúc thiết bị được kết nối với mạng wifi nhưng không cung cấp truy cập internet! Trong tình huống này, cách này xác định việc thiếu quyền truy cập Internet ... các cách khác - không! 2. Bạn có thể sử dụng máy chủ của riêng mình thay vì google.com ... Điều này ban đầu có nghĩa là ...
Dmitry

1
giải pháp kém, kẻ giết kết nối.
gokhanakkurt

2
gokhanakkurt, xin vui lòng, đề nghị một giải pháp khác để đảm bảo rằng các hoạt động Internet ở 100%
Dmitry

15

Đối với Swift 3.1 (iOS 10.1)

Nếu bạn muốn phân biệt loại mạng (tức là WiFi hoặc WWAN):

Bạn có thể dùng:

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

Đây là toàn bộ Reachability-Class phân biệt giữa các loại mạng:

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

hoạt động tốt từ ngày 3 tháng 12 năm 2016, iOS 10 và swift 3.1, cảm ơn!
joey

Xin chào, nếu chúng tôi muốn phân biệt kết nối Wifi / 3G / Di động-Dữ liệu / 4G để làm cách nào chúng tôi có thể xác định.

6

Vì sendSynchronousRequest không được dùng nữa, tôi đã thử điều này nhưng 'Trạng thái trả lại' đã được gọi trước khi phản hồi kết thúc.

Câu trả lời này hoạt động tốt mặc dù, Kiểm tra kết nối Internet với Swift

Đây là những gì tôi đã thử:

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

Tôi thích và sử dụng giải pháp của bạn. Nhưng tôi đã thêm một kết hợp nó với câu trả lời này: stackoverflow.com/a/34591379 aka. tôi đã thêm một semaphore .. Vì vậy, tôi đợi nhiệm vụ kết thúc.
Bjqn

6

SWIFT 3: Kiểm tra kết nối wifiinternet :

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

SỬ DỤNG:

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

2
public func isConnectedToNetwork() {...}nên được thay đổi thành class func isConnectedToNetwork{...}cho trường hợp sử dụng của bạn.
keverly

4

Bạn cũng có thể sử dụng câu trả lời bên dưới.

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

Cảm ơn! Tôi nhận được phản hồi tự động sửa lỗi là NSHTTPURLResponse? để trả lời như! NSHTTPURL Phản hồi? trong Swift 1.2.
Francis Jervis

1

SWIFT 3: Kiểm tra kết nối 3G và 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()
}

Đây không phải là một cách ưa thích. Điều gì sẽ xảy ra nếu tại một thời điểm nào đó trong tương lai, liên kết web được cung cấp ngừng phản hồi hoặc ngừng hoạt động. Tôi khuyên bạn nên sử dụng khung cấu hình Hệ thống của Apple cho việc này. Xem câu trả lời trên.
Abdul Yasin

1

Đối với 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

Swift 4

if isInternetAvailable() {
    print("if called Internet Connectivity success \(isInternetAvailable())");
} else {
    print("else called Internet Connectivity success \(isInternetAvailable())");
}

func isInternetAvailable() -> Bool {
    var zeroAddress = sockaddr_in()
    zeroAddress.sin_len = UInt8(MemoryLayout.size(ofValue: zeroAddress))
    zeroAddress.sin_family = sa_family_t(AF_INET)
    let defaultRouteReachability = withUnsafePointer(to: &zeroAddress) {
        $0.withMemoryRebound(to: sockaddr.self, capacity: 1) {zeroSockAddress in
            SCNetworkReachabilityCreateWithAddress(nil, zeroSockAddress)
     }
    }

   var flags = SCNetworkReachabilityFlags()

   if !SCNetworkReachabilityGetFlags(defaultRouteReachability!, &flags) {
      return false
   }
   let isReachable = flags.contains(.reachable)
   let needsConnection = flags.contains(.connectionRequired)
   //   print(isReachable && !needsConnection)
   return (isReachable && !needsConnection)
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.