【问题标题】:Check for internet connection availability in Swift检查 Swift 中的互联网连接可用性
【发布时间】:2014-10-13 10:53:14
【问题描述】:

有没有办法使用 Swift 检查互联网连接是否可用?

我知道有很多第三方库可以做到这一点,但它们都是用 Objective-C 编写的。我正在寻找 Swift 替代方案。

【问题讨论】:

  • Swift 的一大优势是它可以很好地与 Objective-C(以及此类库)集成。
  • 确实如此。您在使用现有库之一时遇到什么问题?使用 Swift 的 Objective C 库非常简单,如果你不会用 Swift 编写任何类型的应用程序,那将是极其困难的。
  • @MattGibson 几乎你可以在 ObjC 中做的所有事情都可以在 Swift 中相对轻松地完成。诚然,在这种情况下会有一些额外的行,但仍远非“极其困难”
  • @ByronCoetsee 我包括使用 AppKit 等库。我的意思是,您需要知道如何与 Objective C 库进行交互才能在 Swift 中编写任何有用的东西。
  • 查看 alamofire 答案 - stackoverflow.com/a/46562290/7576100

标签: ios swift network-connection


【解决方案1】:

如果你在你的项目中使用 Alamofire,你可以使用这个示例函数:

import Alamofire

class Network {

    func isConnected(_ complition: @escaping(Bool) -> Void) {
        let retVal = NetworkReachabilityManager()!.isReachable
        complition(retVal)
    }

}

【讨论】:

    【解决方案2】:

    我找到了所有答案中最好的,并且每次都会继续检查 Internet 连接状态。

    要开始,首先为网络框架添加一个导入:

    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)
    

    这里我是如何在我的视图控制器中使用它的,

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

    【讨论】:

    【解决方案3】:

    斯威夫特 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)
    }
    

    【讨论】:

      【解决方案4】:

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

      【讨论】:

      • 好像这行不通,因为你没有这样做monitor.start(queue: someQueue)
      【解决方案5】:

      正如 cmets 中提到的,虽然它可以在 Swift 中使用 Objective-C 库,但我想要一个更纯粹的 Swift 解决方案。现有的 Apple Reachability 类和其他第三方库对于我来说似乎太复杂而无法转换为 Swift。我在 Google 上搜索了更多内容,发现了这个 article,它显示了一种检查网络可用性的简单方法。我开始把它翻译成 Swift。我遇到了很多snags,但感谢来自 StackOverflow 的Martin R,我设法解决了这些问题,并最终在 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

      【讨论】:

      • 感谢您的快速响应(不是双关语)。 MIT 或 Apache 将是理想的 - 谢谢!
      • 完成。改为麻省理工学院。
      • 我发现了另一个问题,如果 3G 已打开但我没有更多数据容量,那么isConnectedToNetwork 返回 true,但我无法调用我的网络服务
      • 正如@Isuru 所说,这是基于stackoverflow.com/a/25623647/1187415,现在已针对Swift 2 进行了更新。
      • @János:现在可以使用 Swift 2 设置通知回调,请参阅更新的答案 stackoverflow.com/a/27142665/1187415
      【解决方案6】:

      SWIFT 3: 检查 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)
          }
      }
      

      用法:

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

      【讨论】:

      • public func isConnectedToNetwork() {...} 应更改为 class func isConnectedToNetwork{...} 以供您使用。
      【解决方案7】:

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

      【讨论】:

      • 这不是首选方式。如果在将来某个时间点提供的 Web 链接停止响应或关闭,该怎么办。我建议为此使用 Apple SystemConfiguration 框架。请参阅上面的答案。
      【解决方案8】:

      适用于 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
          }
      }
      

      这是区分网络类型的整个可达性类:

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

      【讨论】:

      • 自 2016 年 12 月 3 日起运行良好,iOS 10 和 swift 3.1,谢谢!
      • 您好,如果我们想区分 Wifi/3G/Mobile-Data/4G 连接,我们如何识别。
      【解决方案9】:

      由于不推荐使用 sendSynchronousRequest,我尝试了这个,但在响应完成之前调用了“返回状态”。

      这个答案很有效,Check for internet connection with 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。我添加了一个信号量。所以我等待任务完成。
      【解决方案10】:

      你也可以使用下面的答案。

          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?以回应为! NSHTTPURL响应?在 Swift 1.2 中。
      【解决方案11】:

      我给你更好的方法……

      您必须使用此代码创建一个类

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

      非常简单!

      *这种方式是基于维克拉姆波特的回答!

      【讨论】:

      • 请注意,您应该使用此方法而不是上面使用的方法。在需要持续连接的应用程序中,像这种方法的响应检查将导致应用程序在您的互联网连接较差的情况下挂起(即在 Edge/GPRS 上)。请不要使用此解决方案!
      • 不好的方式 1) 每次都需要对服务器进行额外的点击 2) google.com 也可以关闭
      • 1.是的,这种方式每次都需要对服务器进行额外的访问,但它可以 100% 保证互联网可用......有时设备连接到 wifi 网络但不提供互联网访问!在这种情况下,这种方式决定了无法访问互联网......其他方式 - 不! 2.你可以使用自己的服务器代替google.com ...这本来是...
      • 糟糕的解决方案,连接杀手。
      • gokhanakkurt,请提出另一种解决方案,以确保互联网以 100% 运行
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多