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


107

是否可以使用Swift检查互联网连接是否可用?

我知道有很多第三方库可以执行此操作,但是它们都是用Objective-C编写的。我正在寻找Swift的替代方案。


5
Swift的巨大好处之一是它与Objective-C(以及此类库)很好地集成在一起。
user2864740 2014年

确实。您在使用现有库之一时遇到什么问题?使用Swift中的Objective C库非常简单,如果您做不到的话,这将证明您用Swift编写任何类型的应用程序都非常困难。
马特·吉布森

1
@MattGibson几乎可以在ObjC中完成的所有操作都可以在Swift中轻松完成。当然,在这种情况下,会有一些额外的提示,但距离“极端困难”还差得远
Byron Coetsee 2014年

@ByronCoetsee我曾经使用过AppKit等库。我的观点是,您需要知道如何与Objective C库进行交互,以便在Swift中编写任何有用的东西。
马特·吉布森

Answers:


227

如评论中所述,尽管可以在Swift中使用Objective-C库,但我想要一个更纯粹的Swift解决方案。现有的Apple Reachability类和其他第三方库对于我来说转换为Swift似乎太复杂了。我用Google搜索了更多内容,然后发现本文显示了一种检查网络可用性的简单方法。我着手将其翻译为Swift。我遇到了很多麻烦,但是由于来自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


7
感谢您的迅速回应(无双关语)。MIT或Apache将是理想的-谢谢!
Andrew Ebling 2014年

4
做完了 将其更改为MIT。
Isuru 2014年

11
我发现另一个问题,如果3G被打开,但我再没有更多的数据容量isConnectedToNetwork返回true,但我不能把我的web服务
亚诺什

11
作为@Isuru说,这是基于stackoverflow.com/a/25623647/1187415,目前已进行了更新,斯威夫特2
马丁- [R

2
@János:现在可以使用Swift 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
  }
}

然后,您可以使用以下代码检查项目中任何地方的Internet连接:

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

好简单!

*这种方式基于Vikram Pote的答案!


15
请注意,您应使用在上述中使用的这种方法。在需要持续连接的应用程序中,类似这种方法的响应检查将导致您的应用程序在互联网连接较差的情况下挂起(例如,在Edge / GPRS上)。请不要使用此解决方案!!
伊姆兰·艾哈迈德

7
不好的方法1)需要服务器命中时间更多的额外时间2)google.com也可能会关闭
Vijay Singh Rana

2
1.是的,这种方式每次都需要对服务器造成额外的打击,但是它可以100%保证Internet可用...有时设备连接到wifi网络但不提供Internet访问!在这种情况下,这种方式决定了无法访问Internet ...其他方式-否!2.您可以使用自己的服务器来代替google.com ...这原本是为了...
Dmitry

1
解决方案差,连接杀手.。
gokhanakkurt,2015年

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

截至2016年12月3日,iOS 10和Swift 3.1正常运行,谢谢!
joey

您好,如果我们想区分Wifi / 3G / Mobile-Data / 4G连接,我们将如何识别。

6

由于不建议使用sendSynchronousRequest,因此我尝试了此操作,但是在响应完成之前调用了“返回状态”。

这个答案很好用,请检查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{...}适合您的使用情况。
凯弗利'17

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?以回应为!NSHTTPURLResponse?在Swift 1.2中。
弗朗西斯·杰维斯

1

SWIFT 3:检查3G和W​​i-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框架。请参阅上面的答案。
阿卜杜勒·亚辛

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)
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.