检查 Swift 中的互联网连接可用性

Posted

技术标签:

【中文标题】检查 Swift 中的互联网连接可用性【英文标题】:Check for internet connection availability in 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 答案 - ***.com/a/46562290/7576100 【参考方案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."
              
        
    
 

【讨论】:

请感谢 Hacking With Swift 这个答案! hackingwithswift.com/example-code/networking/…【参考方案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,但感谢来自 *** 的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 所说,这是基于***.com/a/25623647/1187415,现在已针对Swift 2 进行了更新。 @János:现在可以使用 Swift 2 设置通知回调,请参阅更新的答案 ***.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
    

【讨论】:

我喜欢并使用了您的解决方案。但我添加了一个与这个答案相结合的:***.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% 运行

以上是关于检查 Swift 中的互联网连接可用性的主要内容,如果未能解决你的问题,请参考以下文章

应用程序启动时如何检查可用的互联网连接[重复]

如何以编程方式检查 Android 中互联网连接的可用性?

如何使用 C# 检查服务调用的互联网连接可用性? [复制]

如何检查 Wifi 中的可用网络

如何正确处理 iOS 中的互联网连接不可用?

如何在android中检查当前的互联网连接是不是可用