web-dev-qa-db-ja.com

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

この質問は他の多くの人にだまされているように見えますが、単純なケースがここで十分に説明されているとは感じません。 AndroidおよびBlackBerryのバックグラウンドから来て、使用可能な接続がない場合、HTTPUrlConnectionを介した要求をすぐに失敗します。これは完全に正気な振る舞いのようで、iOSのNSURLConnectionがエミュレートしていないことに驚いた。

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

私のアプリは、接続性を含め、接続障害をすでに正常に処理しています。ユーザーに障害が通知され、アプリが続行します。

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

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

146
RealCasually

私はもう少し研究を行い、現在の解決策で答えを更新しています。あなたがすでにそれを見たかどうかはわかりませんが、Appleから提供されているNiceサンプルコードがあります。

サンプルコードをダウンロード here

プロジェクトに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をプロジェクトに追加することを忘れないでください。

249

このスレッドがこのタイプの質問に対する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;
}
45
sherbertman

返信が遅すぎて申し訳ありませんが、この回答が将来誰かに役立つことを願っています。

以下は、追加のクラスなしでインターネット接続を確認できる小さなネイティブ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;
    }
}

Swift

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

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

インポート:

#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

31
GilesDMiddleton

実装を完了するときにそれを見ると、それは可能であり、本当に簡単です。必要なのは、インターネット到達可能性とホスト到達可能性という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
11
Danut Pralea

誰かhasが以前、これを簡単で再利用可能な方法で解決しました。 DDGReachability

編集:または tonymillion/Reachability

6
darvids0n

コードを抽出して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;


}
4
Walty Yeung

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

[[AFNetworkReachabilityManager sharedManager] startMonitoring];

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

受け入れられた答えのSwiftバージョンを書いています ここ 、誰かがそれを有用と思う場合に備えて、コードはSwift 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
Satyen Udeshi

プロジェクトですでに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;
}
}
2

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")
}
1
blwinters

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

IOS 5の時点で、新しいNSURLインスタンスメソッドがあります。

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

関心のあるWebサイトを指すようにするか、Apple.comを指すようにします。インターネットがデバイスで動作しているかどうかを確認するのは、新しい1行の呼び出しだと思います。

0
SG1

AppleのReachabilityの代わりに、in Swift in Closuresがtonymillionに触発されて: https://github.com/ashleymills/ Reachability.Swift

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

  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
Pierre F

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

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

https://github.com/fareast555/TFInternetChecker

0
Mike Critchley

(iOS)Xcode 8.2でのインターネット接続の可用性の確認、Swift 3.

これは、ネットワークの可用性を確認する簡単な方法です。私はそれを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")
}
0
ViJay Avhad

アラモファイア

すでにすべてのRESTful APIでAlamofireを使用している場合は、そこからメリットを得ることができます。

次のクラスをアプリに追加し、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
  }
}

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

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

0
nuynait