iOSでインターネット接続を検出する最も簡単な方法は?


147

この質問は他の多くの人のだましのように見えることは知っていますが、単純なケースがここで十分に説明されているとは思いません。AndroidおよびBlackBerryのバックグラウンドから来ており、HTTPUrlConnection接続が利用できない場合、リクエストの送信はすぐに失敗します。これは完全に正常な動作のように見えNSURLConnection、iOSでエミュレートされていないことに気付いて驚いた。

Apple(およびそれを拡張した他の人)Reachabilityがネットワーク状態の判別を支援するクラスを提供していることを理解しています。私はこれを最初に見てうれしかったですがbool isNetworkAvailable()、のようなものを完全に期待していましたが、驚いたことに、通知の登録とコールバックを必要とする複雑なシステムと、一見不要な詳細の束を見つけました。もっと良い方法があるはずです。

私のアプリは既に、接続の失敗など、接続の失敗を適切に処理しています。ユーザーは失敗を通知され、アプリは次に進みます。

したがって、私の要件は単純です。すべてのHTTP要求の前に呼び出すことができる単一の同期関数で、実際に要求を送信する必要があるかどうかを判断できます。理想的には、セットアップは必要なく、ブール値を返すだけです。

これはiOSでは本当に不可能ですか?



すべてのHTTPリクエストの前に、同期ネットワーク到達可能性メソッドを呼び出さないでください。到達可能性がネットワーク状態に変化があったことを非同期的に通知せず、HTTPリクエストを送信しないことを選択できる場合を除いて、この作業を行うのはちょっとおかしいです。これは、タイムアウトが存在する理由全体でもあります(そのシナリオを適切に処理する必要があります)。非同期の方法については上記のリンクを参照してください
iwasrobbed

回答:


251

私はもう少し調査を行い、より最新の解決策で私の答えを更新しています。あなたがすでにそれを見てきたかどうかはわかりませんが、アップルから提供されている素晴らしいサンプルコードがあります。

ここからサンプルコードをダウンロードしてください

Reachability.hファイルとReachability.mファイルをプロジェクトに含めます。ReachabilityAppDelegate.mを見て、ホストの到達可能性、WiFiによる到達可能性、WWANによる到達可能性などを判断する方法の例を確認してください。ネットワークの到達可能性を非常に簡単に確認するには、次のようにします。

Reachability *networkReachability = [Reachability reachabilityForInternetConnection];   
NetworkStatus networkStatus = [networkReachability currentReachabilityStatus];    
if (networkStatus == NotReachable) {        
    NSLog(@"There IS NO internet connection");        
} else {        
     NSLog(@"There IS internet connection");        
}

@ BenjaminPiette's:SystemConfiguration.frameworkをプロジェクトに追加することを忘れないでください。


46
プロジェクトにSystemConfiguration.frameworkを追加することを忘れないでください。
Benjamin Piette、

1
@chandru動作します。これは、ネットワーク接続を検出するために私が見る最も簡単で効果的な方法です。シンプルで簡単!
S1U 2014

3
これに注意してください。少なくともシミュレータでは、ネットワークが復元されたときに確実に機能しないことがわかりました。私はwifiをオフにして起動すると、利用可能なネットワークがないことを正しく報告します。しかし、その後wifiを再びオンにすると、実際のネットワーククエリは正常に機能しますが、SCNetworkReachabilityGetFlagsは引き続き0を返します。
ジョーストラウト2014

2
以下の私の答え(stackoverflow.com/a/26593728/557362)は必要な作業が少ない(他のファイルをダウンロードしない)と思いますが、それは私の意見です。
GilesDMiddleton 2014年

3
これは、特定のホストへの接続がルーティング可能かどうかを通知するだけであることに注意してください。これは、実際に接続できるという意味ではありません。例:iPhoneのwifiをカメラのwifiに接続します。Wifiはデフォルトゲートウェイに接続されています。すべてのホストが到達可能と報告します。しかし、実際にはそうではありません。カメラは行き止まりの接続です。
xaphod 2016年

45

このスレッドがこのタイプの質問に対するGoogleの上位の結果であることを考えて、私は私に役立つ解決策を提供すると思いました。私はすでにAFNetworkingを使用していましたが、プロジェクトの途中まで、検索でAFNetworkingを使用してこのタスクを実行する方法がわかりませんでした。

必要なのは AFNetworkingReachabilityManagerです。

// -- Start monitoring network reachability (globally available) -- //
[[AFNetworkReachabilityManager sharedManager] startMonitoring];

[[AFNetworkReachabilityManager sharedManager] setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {

    NSLog(@"Reachability changed: %@", AFStringFromNetworkReachabilityStatus(status));


    switch (status) {
        case AFNetworkReachabilityStatusReachableViaWWAN:
        case AFNetworkReachabilityStatusReachableViaWiFi:
            // -- Reachable -- //
            NSLog(@"Reachable");
            break;
        case AFNetworkReachabilityStatusNotReachable:
        default:
            // -- Not reachable -- //
            NSLog(@"Not Reachable");
            break;
    }

}];

以下を使用して、到達可能性を同期的にテストすることもできます(監視が開始されたら)。

-(BOOL) isInternetReachable
{
    return [AFNetworkReachabilityManager sharedManager].reachable;
}

3
AFNetworkReachabilityManager光を当てることに賛成しました!
セルビン2014年

これがすぐにはわからなかった人のために:AFNetworkingはサードパーティのライブラリです。
arlomedia、2015年

1
ネットワーク到達可能性は、要求が失敗した理由を理解するために使用できる診断ツールです。リクエストを行うかどうかの判断には使用しないでください。-それはドキュメンテーションが言うことです。
Nosov Pavel

AFNetworkReachabilityManager.reachableいかなる種類の同期チェックも実行しません。これは、論理的またはのを返すreachableViaWWANreachableViaWifi
jdolan 2015

40

返信が遅すぎて申し訳ありませんが、この回答が将来の誰かのお役に立てば幸いです。

以下は、追加のクラスなしでインターネット接続をチェックできる小さなネイティブCコードスニペットです。

次のヘッダーを追加します。

#include<unistd.h>
#include<netdb.h>

コード:

-(BOOL)isNetworkAvailable
{
    char *hostname;
    struct hostent *hostinfo;
    hostname = "google.com";
    hostinfo = gethostbyname (hostname);
    if (hostinfo == NULL){
        NSLog(@"-> no connection!\n");
        return NO;
    }
    else{
        NSLog(@"-> connection established!\n");
        return YES;
    }
}

スウィフト3

func isConnectedToInternet() -> Bool {
    let hostname = "google.com"
    //let hostinfo = gethostbyname(hostname)
    let hostinfo = gethostbyname2(hostname, AF_INET6)//AF_INET6
    if hostinfo != nil {
        return true // internet available
      }
     return false // no internet
    }

3
Appleの到達可能性よりもはるかに優れています。しかし、ドキュメントによると、gethostbynameは廃止されており、getaddrinfoを使用する必要があります。struct addrinfo * res = NULL; int s = getaddrinfo( "apple.com"、NULL、NULL、&res); bool network_ok =(s == 0 && res!= NULL); freeaddrinfo(res);
Tertium 2013年

1
インターネットの可用性を確認するためにgoogle.comを使用することは一般的ですが、一部の国ではブロックされていることは注目に値します。より適切な選択は、yahoo.comやmicrosoft.comなど、より「政府に優しい」企業のドメインです。
ローレント2013年

8
@Laurent:データをリクエストするサーバーアドレスを使用するのが最善の方法です。こちらのgoogle.comは一例です。
dispatchMain

7
これはDNSルックアップを行っているだけですか?もしそうなら、キャッシュされたDNS結果は、ネットワークが利用可能であると誤って信じる機能をもたらす可能性がありますか?
Stephen Moore 14年

2
@amarループでこれを実行すると、ワイヤレスデータが消費されます。これを行う必要はありません。
意味の重要性

31

私は現在、プロジェクトまたはデリゲートに追加のファイルを必要としない、この単純な同期方法を使用しています。

インポート:

#import <SystemConfiguration/SCNetworkReachability.h>

このメソッドを作成します。

+(bool)isNetworkAvailable
{
    SCNetworkReachabilityFlags flags;
    SCNetworkReachabilityRef address;
    address = SCNetworkReachabilityCreateWithName(NULL, "www.apple.com" );
    Boolean success = SCNetworkReachabilityGetFlags(address, &flags);
    CFRelease(address);

    bool canReach = success
                    && !(flags & kSCNetworkReachabilityFlagsConnectionRequired)
                    && (flags & kSCNetworkReachabilityFlagsReachable);

    return canReach;
}

次に、これをに入れた場合MyNetworkClass

if( [MyNetworkClass isNetworkAvailable] )
{
   // do something networky.
}

シミュレーターでテストしている場合は、シミュレーターが電話の設定を無視しているように見えるため、Macのwifiのオンとオフを切り替えます。

更新:

  1. 最後に、メインスレッドのブロックを回避するために、スレッド/非同期コールバックを使用しました。定期的に再テストして、キャッシュされた結果を使用できるようにしました。ただし、データ接続を不必要に開いたままにしないでください。

  2. @thunkが説明したように、Apple自身が使用するより良いURLがあります。http://cadinc.com/blog/why-your-apple-ios-7-device-wont-connect-to-the-wifi-network


1
おかげで、このスレッドの他のほとんどの人と同じです。プロジェクトにSystemConfiguration.frameworkを追加することを忘れないでください。
eselk 2015年

1
奇妙なことに、私のXcodeプロジェクトでは、SystemConfiguration.frameworkを追加する必要はありませんでした。SpriteKit、UIKit、StoreKit、Foundation、CoreGraphicsは持っていますが、SystemConfigurationは持っていません。...暗黙的な組み込みが行われていますか?
GilesDMiddleton、2015年

3
これでうまくいきましたが、インターネットに接続されていないwi-fiネットワークに接続して実行すると、UIが約30秒間ロックされました。そのような状況では、非同期のアプローチが必要です。
arlomedia

2
www.apple.com大きなウェブサイトです...より良いオプションはwww.google.com
次のとおり

2
すばらしい答え!1つの提案:テストURLはwww.appleiphonecell.com、この目的のためにのみ利用可能であり、中国ではブロックされていないようです。
サンク

11

可能であり、実装を完了するときにそれを見ると本当に簡単です。これも非常に簡単です。必要な項目は、ブール値の2つの変数、つまりインターネット到達可能性とホスト到達可能性だけです(多くの場合、これらの1つ以上が必要です)。 )。接続ステータスを判別できるヘルパークラスをアセンブルしたら、これらの手順を理解するために必要な実装を再び気にする必要はありません。

例:

#import <Foundation/Foundation.h>

@class Reachability;

@interface ConnectionManager : NSObject {
    Reachability *internetReachable;
    Reachability *hostReachable;
}

@property BOOL internetActive;
@property BOOL hostActive;

- (void) checkNetworkStatus:(NSNotification *)notice;

@end

そして.mファイル:

#import "ConnectionManager.h"
#import "Reachability.h"

@implementation ConnectionManager
@synthesize internetActive, hostActive;

-(id)init {
    self = [super init];
    if(self) {

    }
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(checkNetworkStatus:) name:kReachabilityChangedNotification object:nil];

    internetReachable = [[Reachability reachabilityForInternetConnection] retain];
    [internetReachable startNotifier];

    hostReachable = [[Reachability reachabilityWithHostName:@"www.apple.com"] retain];
    [hostReachable startNotifier];

    return self;
}

- (void) checkNetworkStatus:(NSNotification *)notice {
    NetworkStatus internetStatus = [internetReachable currentReachabilityStatus];
    switch (internetStatus)

    {
        case NotReachable:
        {
            NSLog(@"The internet is down.");
            self.internetActive = NO;

            break;

        }
        case ReachableViaWiFi:
        {
            NSLog(@"The internet is working via WIFI.");
            self.internetActive = YES;

            break;

        }
        case ReachableViaWWAN:
        {
            NSLog(@"The internet is working via WWAN.");
            self.internetActive = YES;

            break;

        }
    }

    NetworkStatus hostStatus = [hostReachable currentReachabilityStatus];
    switch (hostStatus)

    {
        case NotReachable:
        {
            NSLog(@"A gateway to the host server is down.");
            self.hostActive = NO;

            break;

        }
        case ReachableViaWiFi:
        {
            NSLog(@"A gateway to the host server is working via WIFI.");
            self.hostActive = YES;

            break;

        }
        case ReachableViaWWAN:
        {
            NSLog(@"A gateway to the host server is working via WWAN.");
            self.hostActive = YES;

            break;

        }
    }

}

// If lower than SDK 5 : Otherwise, remove the observer as pleased.

- (void)dealloc {
    [[NSNotificationCenter defaultCenter] removeObserver:self];
    [super dealloc];
}

@end


4

私はコードを抽出して1つのメソッドに入れました。他の人の役に立つことを願っています。

#import <SystemConfiguration/SystemConfiguration.h>

#import <netinet/in.h>
#import <netinet6/in6.h>

...

- (BOOL)isInternetReachable
{    
    struct sockaddr_in zeroAddress;
    bzero(&zeroAddress, sizeof(zeroAddress));
    zeroAddress.sin_len = sizeof(zeroAddress);
    zeroAddress.sin_family = AF_INET;

    SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (const struct sockaddr*)&zeroAddress);
    SCNetworkReachabilityFlags flags;

    if(reachability == NULL)
        return false;

    if (!(SCNetworkReachabilityGetFlags(reachability, &flags)))
        return false;

    if ((flags & kSCNetworkReachabilityFlagsReachable) == 0)
        // if target host is not reachable
        return false;


    BOOL isReachable = false;


    if ((flags & kSCNetworkReachabilityFlagsConnectionRequired) == 0)
    {
        // if target host is reachable and no connection is required
        //  then we'll assume (for now) that your on Wi-Fi
        isReachable = true;
    }


    if ((((flags & kSCNetworkReachabilityFlagsConnectionOnDemand ) != 0) ||
         (flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) != 0))
    {
        // ... and the connection is on-demand (or on-traffic) if the
        //     calling application is using the CFSocketStream or higher APIs

        if ((flags & kSCNetworkReachabilityFlagsInterventionRequired) == 0)
        {
            // ... and no [user] intervention is needed
            isReachable = true;
        }
    }

    if ((flags & kSCNetworkReachabilityFlagsIsWWAN) == kSCNetworkReachabilityFlagsIsWWAN)
    {
        // ... but WWAN connections are OK if the calling application
        //     is using the CFNetwork (CFSocketStream?) APIs.
        isReachable = true;
    }


    return isReachable;


}

[A]このコードをどこから抽出しましたか?ソースへのリンクを投稿できますか?[B]抽出作業をありがとうございました!ちょうど私が必要としたもの。私はこの雑用を自分でやろうとしていました。
バジルブルク2013年

それで、これはリモートサーバーをチェックしない唯一の答えのようです?
Jasper、

MacOSでこれをテストしている他の人にとっては、kSCNetworkReachabilityFlagsIsWWANはmacOSではなくOS_IPHONE用であることに注意してください。
GeoffCoope 2017

4

受け入れられた回答の迅速なバージョンをここに書いていますで。誰かがそれを便利だと思った場合、コードは迅速に書かれています2、

SampleCodeから必要なファイルをダウンロードできます

プロジェクトに追加Reachability.hしてReachability.mファイルし、

Bridging-Header.hプロジェクトにファイルがない場合は、ファイルを作成する必要があります。

Bridging-Header.hファイル内に次の行を追加します。

#import "Reachability.h"

インターネット接続を確認するために

static func isInternetAvailable() -> Bool {
    let networkReachability : Reachability = Reachability.reachabilityForInternetConnection()
    let networkStatus : NetworkStatus = networkReachability.currentReachabilityStatus()

    if networkStatus == NotReachable {
        print("No Internet")
        return false
    } else {
        print("Internet Available")
        return true
    }

}

3

これが役立つと思います。

[[AFNetworkReachabilityManager sharedManager] startMonitoring];

if([AFNetworkReachabilityManager sharedManager].isReachable)
{
    NSLog(@"Network reachable");
}
else
{   
   NSLog(@"Network not reachable");
}

これは、ネットワークインターフェイスが変更されておらず、インターネット接続が失われている場合は機能しません。
Pratik Somaiya 2017年

2

プロジェクトでAFNetworkingをすでに構成している場合も、これを試すことができます。

-(void)viewDidLoad{  // -- add connectivity notification --//
[[NSNotificationCenter defaultCenter ] addObserver:self selector:@selector(ReachabilityDidChangeNotification:) name:AFNetworkingReachabilityDidChangeNotification object:nil];}
-(void)ReachabilityDidChangeNotification:(NSNotification *)notify
{
// -- NSLog(@"Reachability changed: %@", AFStringFromNetworkReachabilityStatus(status));  -- //
NSDictionary *userInfo =[notif userInfo];
AFNetworkReachabilityStatus status= [[userInfo valueForKey:AFNetworkingReachabilityNotificationStatusItem] intValue];
switch (status)
{
    case AFNetworkReachabilityStatusReachableViaWWAN:
    case AFNetworkReachabilityStatusReachableViaWiFi:
        // -- Reachable -- //
// -- Do your stuff when internet connection is available -- //
        [self getLatestStuff];
        NSLog(@"Reachable");
        break;
    case AFNetworkReachabilityStatusNotReachable:
    default:
        // -- Not reachable -- //
        // -- Do your stuff for internet connection not available -- //
NSLog(@"Not Reachable");
        break;
}
}

1

Reachabilityを使用せずにSwiftを使用して接続を確認するための適切なソリューションを次に示します。このブログで見つけました。

Network.swift(たとえば)というプロジェクトに新しいSwiftファイルを作成します。このコードをそのファイル内に貼り付けます。

import Foundation

public class Network {

    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 Network.isConnectedToNetwork() == true {
    println("Internet connection OK")
} else {
    println("Internet connection FAILED")
}

0

編集:これはネットワークURLでは機能しません(コメントを参照)

iOS 5以降、新しいNSURLインスタンスメソッドがあります。

- (BOOL)checkResourceIsReachableAndReturnError:(NSError **)error

気になるWebサイトを指すようにするか、apple.comを指すようにします。これは、デバイスでインターネットが機能しているかどうかを確認するための新しい1行の呼び出しだと思います。


実際、私自身のテストでは、これは常にfalseを返します。ドキュメントは、これが4.xの場合に当てはまると述べていますが、5 +以降では機能するはずです。YMMV
SG1

これは、探している状況では機能しないようです。stackoverflow.com/questions/9266154/…を
Micah

7
これは、インターネットURLではなく、ファイルURLに使用されます。
ビクターボグダン

0

利用可能なインターネットチェックオプションにも満足していませんでした(なぜこれがネイティブAPIではないのですか?!?!)

私自身の問題は、100%のパケット損失でした-デバイスがルーターに接続されているが、ルーターがインターネットに接続されていない場合。到達可能性などは、長い間ハングします。非同期タイムアウトを追加することで、これに対処するユーティリティシングルトンクラスを作成しました。私のアプリでは問題なく動作します。それが役に立てば幸い。github上のリンクは次のとおりです。

https://github.com/fareast555/TFInternetChecker


0

(iOS)Xcode 8.2、Swift 3.0でインターネット接続の可用性を確認する

これは、ネットワークの可用性を確認する簡単な方法です。私はなんとかそれをSwift 2.0に、そしてここでは最終的なコードに翻訳しました。既存のApple Reachabilityクラスと他のサードパーティのライブラリは、Swiftに変換するには複雑すぎるようです。

これは、3G接続とWiFi接続の両方で機能します。

プロジェクトビルダーに「SystemConfiguration.framework」を追加することを忘れないでください。

//Create new swift class file Reachability in your project.

import SystemConfiguration

public class Reachability {
class func isConnectedToNetwork() -> 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.rawValue & UInt32(kSCNetworkFlagsReachable)) != 0
    let needsConnection = (flags.rawValue & UInt32(kSCNetworkFlagsConnectionRequired)) != 0
    return (isReachable && !needsConnection)
   }
}

// Check network connectivity from anywhere in project by using this code.

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

Xcodeバージョン7.2(7C68)では、このコードにコンパイラエラーがあります
Daniel

@Daniel、問題を指摘してくれてありがとう、これは安全でないポインタのためです。Swift2 / Xcodeがそこで構文を更新しているので、それらに従う必要があります。私は同じためにコードを更新しました。ty;)
ViJay Avhad

Wi-Fiに接続しているがインターネットに接続できない(Googleページを開く)場合でも、到達可能の場合はtrueを返します。それは間違っています。
Arildo Junior 2017

0

tonymillionに触発されたSwiftでクロージャーで書き直されたAppleの到達可能性の代替:https : //github.com/ashleymills/Reachability.swift

  1. ファイルReachability.swiftをプロジェクトにドロップします。または、CocoaPodsまたはCarthageを使用します- プロジェクトのREADMEの「インストール」セクションを参照してください。

  2. ネットワーク接続に関する通知を取得します。

    //declare this property where it won't go out of scope relative to your listener
    let reachability = Reachability()!
    
    reachability.whenReachable = { reachability in
        if reachability.isReachableViaWiFi {
            print("Reachable via WiFi")
        } else {
            print("Reachable via Cellular")
        }
    }
    
    reachability.whenUnreachable = { _ in
        print("Not reachable")
    }
    
    do {
        try reachability.startNotifier()
    } catch {
        print("Unable to start notifier")
    }

    通知を停止するため

    reachability.stopNotifier()

0

アラモファイア

すでにAlamofireを使用している場合すべてのRESTfulでをいる場合は、そのメリットを以下に示します。

次のクラスをアプリに追加し、呼び出しMNNetworkUtils.main.isConnected()て、接続されているかどうかのブール値を取得できます。

#import Alamofire

class MNNetworkUtils {
  static let main = MNNetworkUtils()
  init() {
    manager = NetworkReachabilityManager(host: "google.com")
    listenForReachability()
  }

  private let manager: NetworkReachabilityManager?
  private var reachable: Bool = false
  private func listenForReachability() {
    self.manager?.listener = { [unowned self] status in
      switch status {
      case .notReachable:
        self.reachable = false
      case .reachable(_), .unknown:
        self.reachable = true
      }
    }
    self.manager?.startListening()
  }

  func isConnected() -> Bool {
    return reachable
  }
}

これはシングルトンクラスです。ユーザーがネットワークを接続または切断するたびに、シングルトンでの初期化のself.reachableリッスンを開始するため、true / falseに正しくオーバーライドさNetworkReachabilityManagerれます。

また、到達可能性を監視するために、ホストを提供する必要があります。現在、私はgoogle.com必要に応じて、他のホストまたはあなたのホストに自由に変更して使用しています。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.