Swift에서 인터넷 연결 가능 여부 확인


107

Swift를 사용하여 인터넷 연결이 가능한지 확인하는 방법이 있습니까?

이를 수행하는 많은 타사 라이브러리가 있지만 모두 Objective-C로 작성되었습니다. Swift 대안을 찾고 있습니다.


5
Swift의 큰 이점 중 하나는 Objective-C (및 이러한 라이브러리)와 잘 통합된다는 것입니다.
user2864740

과연. 기존 라이브러리 중 하나를 사용하는 데 어떤 문제가 있습니까? Swift의 Objective C 라이브러리를 사용하는 것은 매우 간단하며, 할 수없는 경우 Swift로 어떤 종류의 앱도 작성하는 것이 극도로 어려울 것입니다.
Matt Gibson

1
@MattGibson ObjC에서 할 수있는 거의 모든 것을 Swift에서 비교적 쉽게 할 수 있습니다. 설령,이 경우 몇 가지 추가 라인하지만 여전히까지 "매우 어려운"에서있을 것입니다
바이런 Coetsee

@ByronCoetsee 저는 AppKit 등과 같은 라이브러리 사용을 포함 시켰습니다. 제 요점은 Swift에서 유용한 것을 작성하려면 Objective C 라이브러리와 상호 작용하는 방법을 알아야한다는 것입니다.
Matt Gibson

alamofire 답변을 참조하십시오 - stackoverflow.com/a/46562290/7576100

답변:


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

4
끝난. MIT로 변경했습니다.
Isuru

11
다른 문제를 발견했습니다. 3G가 켜져 있지만 더 이상 데이터 용량이없는 isConnectedToNetwork경우 true 를 반환 하지만 웹 서비스를 호출 할 수 없습니다
János

11
@Isuru가 말했듯이 이것은 stackoverflow.com/a/25623647/1187415를 기반으로하며 , 현재 Swift 2 용으로 업데이트되었습니다.
Martin 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
  }
}

그런 다음이 코드를 사용하여 프로젝트의 어느 곳에서나 인터넷 연결을 확인할 수 있습니다.

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

아주 쉽게!

*이 방법은 Vikram Pote 답변을 기반으로합니다!


15
위에서 사용한 방법보다이 방법을 사용 해서는 안됩니다 . 지속적인 연결이 필요한 애플리케이션에서이 방법과 같은 응답 확인을 수행하면 인터넷 연결이 좋지 않은 상황 (예 : Edge / GPRS)에서 앱이 중단됩니다. 이 솔루션을 사용하지 마십시오 !!
Imran Ahmed

7
나쁜 방법 1) 서버 에브리 시간에 추가 타격을 필요 2) google.com 도 다운 될 수 있습니다
비제이 싱 (피지)라나

2
1. 예, 이렇게하면 매번 서버에 추가 공격이 필요하지만 인터넷 사용을 100 % 보장합니다 ... 장치가 Wi-Fi 네트워크에 연결되어 있지만 인터넷 액세스를 제공하지 않는 경우가 있습니다! 이 상황 에서이 방법은 인터넷에 대한 액세스 부족을 결정합니다 ... 다른 방법은 아닙니다! 2. 당신이 사용할 수있는 자신의 서버 대신 google.com ...이 원래 의미되었다 ...
드미트리

1
불쌍한 솔루션, 연결 킬러.
gokhanakkurt 2015

2
gokhanakkurt는 다른 해결책을 제안 해주십시오 보장 100 % 인터넷 작동하는지
드미트리

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

다음은 네트워크 유형을 구분하는 전체 도달 가능성 클래스입니다.

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 및 신속한 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 일명. 세마포어를 추가했습니다. 그래서 작업이 끝날 때까지 기다립니다.
Bjqn

6

SWIFT 3 : 에 대한 확인 와이파이인터넷 연결 :

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로 응답에서 자동 수정을 받았습니까? 응답으로! NSHTTPURLResponse? Swift 1.2에서.
Francis Jervis 2015

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 프레임 워크를 사용하는 것이 좋습니다. 위의 답변을 참조하십시오.
Abdul Yasin

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)
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.