Swiftでインターネット接続の可用性を確認する


107

Swiftを使用してインターネット接続が利用可能かどうかを確認する方法はありますか?

これを行うためのサードパーティのライブラリがたくさんあることは知っていますが、それらはすべてObjective-Cで記述されています。Swiftの代替案を探しています。


5
Swiftの大きな利点の1つは、Objective-C(およびそのようなライブラリ)とうまく統合できることです。
user2864740 2014

確かに。既存のライブラリの1つを使用すると、どのような問題が発生しますか?SwiftのObjective Cライブラリを使用するのは非常に簡単です。できなければ、Swiftであらゆる種類のアプリを作成することは非常に困難です。
マットギブソン

1
@MattGibsonは、ObjCで実行できるほとんどすべてのことを比較的簡単にSwiftで実行できます。確かに、この場合、いくつかの余分な行がありますが、それでも「非常に難しい」とは
ほど遠い

@ByronCoetsee AppKitなどのライブラリの使用を含めていました—私のポイントは、Swiftで有用なものを書くためにObjective Cライブラリと対話する方法を知る必要があるということです。
Matt Gibson

alamofire答えを参照してください- stackoverflow.com/a/46562290/7576100
ジャック

回答:


227

コメントで述べたように、SwiftでObjective-Cライブラリを使用することは可能ですが、より純粋なSwiftソリューションが必要でした。既存のApple Reachabilityクラスと他のサードパーティのライブラリは、Swiftに変換するには複雑すぎるようです。さらにグーグル検索したところ、ネットワークの可用性を確認する簡単な方法を示すこの記事に出くわしました。これを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がオンになっているが、私はこれ以上のデータ容量が続いていisConnectedToNetworktrueを返します、しかし、私は自分の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
  }
}

次に、このコードを使用して、プロジェクトのどこでもインターネット接続を確認できます。

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

非常に簡単!

*この方法はVikram Poteの回答に基づいています!


15
上記で使用した方法よりもこの方法を使用しないでください。常時接続を必要とするアプリケーションでは、このメソッドのような応答チェックを行うと、インターネット接続が不十分な状況(つまり、エッジ/ GPRS)でアプリがハングします。このソリューションは使用しないでください!!
Imran Ahmed

7
悪い方法1)サーバーの評価時間に追加のヒットが必要2)google.comもダウンしている可能性がある
Vijay Singh Rana

2
1.はい、この方法では毎回サーバーに追加のヒットが必要ですが、インターネットが利用可能であることを100%保証します...デバイスがwifiネットワークに接続されていてもインターネットアクセスを提供しない場合があります!この状況では、この方法はインターネットへのアクセスの欠如を決定します...他の方法-いいえ!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は非推奨であるため、これを試しましたが、応答が完了する前に '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 aka。セマフォを追加しました。タスクが完了するのを待ちます。
Bjqn

6

SWIFT 3: をチェック無線LANおよびインターネット接続:

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{...}使用状況に応じてに変更する必要があります。
ケバリー2017

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で。
フランシスジャービス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()
}

これは推奨される方法ではありません。将来のある時点で、提供されたWebリンクが応答を停止するか、ダウンした場合はどうなりますか。これにはApple SystemConfigurationフレームワークを使用することをお勧めします。上記の回答を参照してください。
Abdul Yasin 2017年

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.