web-dev-qa-db-de.com

Einfachste Möglichkeit, eine Internetverbindung unter iOS zu erkennen?

Ich weiß, dass diese Frage als Betrug vieler anderer erscheinen wird. Ich glaube jedoch nicht, dass der einfache Fall hier gut erklärt wird. Von einem Android- und BlackBerry-Hintergrund kommend, schlagen Anforderungen über HTTPUrlConnection sofort fehl, wenn keine Verbindung verfügbar ist. Dies scheint völlig gesundes Verhalten zu sein, und ich war überrascht, dass NSURLConnection in iOS nicht nachgeahmt wurde.

Ich verstehe, dass Apple (und andere, die es erweitert haben) eine Reachability-Klasse bereitstellen, um die Ermittlung des Netzwerkstatus zu unterstützen. Ich war froh, als ich das zum ersten Mal gesehen hatte und erwartete, etwas wie bool isNetworkAvailable() zu sehen, aber zu meiner Überraschung fand ich ein komplexes System, das Benachrichtigungsregistrierungen und Rückrufe sowie eine Reihe scheinbar unnötiger Details erforderte. Es muss einen besseren Weg geben.

Meine App verarbeitet bereits fehlerhaft Verbindungsfehler, darunter auch keine Konnektivität. Der Benutzer wird über den Fehler informiert und die App wird fortgesetzt.

Daher sind meine Anforderungen einfach: Eine einzige, synchrone Funktion, die ich vor allen HTTP-Anforderungen aufrufen kann, um festzustellen, ob ich die Anfrage tatsächlich senden möchte oder nicht. Im Idealfall ist kein Setup erforderlich und es wird nur ein Boolean zurückgegeben.

Ist das unter iOS wirklich nicht möglich?

143
RealCasually

Ich habe ein wenig mehr recherchiert und aktualisiere meine Antwort mit einer aktuelleren Lösung. Ich bin mir nicht sicher, ob Sie es bereits angeschaut haben, aber es gibt einen schönen Beispielcode von Apple. 

Laden Sie den Beispielcode hier herunter 

Schließen Sie die Dateien Reachability.h und Reachability.m in Ihr Projekt ein. Schauen Sie sich ReachabilityAppDelegate.m an, um ein Beispiel zu sehen, wie Sie die Erreichbarkeit von Hosts, die Erreichbarkeit über WLAN, über WWAN usw. ermitteln. Für eine sehr einfache Überprüfung der Erreichbarkeit des Netzwerks können Sie so etwas tun 

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: Vergiss nicht, SystemConfiguration.framework deinem Projekt hinzuzufügen. 

249

Da dieser Thread das Top-Ergebnis von Google für diese Art von Frage ist, dachte ich, ich würde die Lösung anbieten, die für mich funktionierte. Ich habe bereits AFNetworking verwendet, aber die Suche hat nicht ergeben, wie man diese Aufgabe mit AFNetworking bis zur Mitte meines Projekts erledigt.

Was Sie wollen, ist der 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;
    }

}];

Sie können Folgendes auch verwenden, um die Erreichbarkeit synchron zu testen (nachdem die Überwachung gestartet wurde):

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

Es tut mir leid, dass Sie zu spät geantwortet haben, aber ich hoffe, diese Antwort kann in Zukunft jemandem helfen.

Nachfolgend finden Sie ein kleines natives C-Code-Snippet, das die Internetverbindung ohne zusätzliche Klasse prüfen kann.

Fügen Sie die folgenden Kopfzeilen hinzu:

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

Code:

-(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 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
    }
38
execv

Ich verwende derzeit diese einfache, synchrone Methode, für die in Ihren Projekten oder Delegierten keine zusätzlichen Dateien erforderlich sind.

Einführen:

#import <SystemConfiguration/SCNetworkReachability.h>

Erstellen Sie diese Methode:

+(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;
}

Wenn Sie dies in eine MyNetworkClass eingegeben haben:

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

Wenn Sie im Simulator testen, schalten Sie das WLAN Ihres Mac ein und aus, wie es aussieht, der Simulator ignoriert die Telefoneinstellungen.

Aktualisieren:

  1. Am Ende habe ich einen Thread/asynchronen Callback verwendet, um das Blockieren des Hauptthreads zu vermeiden. und regelmäßig neu testen, sodass ich ein zwischengespeichertes Ergebnis verwenden könnte - obwohl Sie vermeiden sollten, dass Datenverbindungen unnötig geöffnet bleiben.

  2. Wie bei @thunk beschrieben, gibt es bessere URLs, die Apple selbst verwendet. http://cadinc.com/blog/why-your-Apple-ios-7-device-wont-connect-to-the-wifi-network

31
GilesDMiddleton

Dies ist möglich und sehr einfach, wenn Sie es beim Abschluss der Implementierung betrachten. Das ist sehr einfach, da Sie lediglich zwei boolesche Variablen benötigen: Internet-Erreichbarkeit und Host-Erreichbarkeit (häufig benötigen Sie mehr als eine dieser Optionen) ). Wenn Sie Ihre Hilfsklasse zusammengestellt haben, die den Verbindungsstatus bestimmen kann, kümmert Sie sich nicht mehr um die Implementierung, die für das Wissen über diese Verfahren erforderlich ist.

Beispiel:

#import <Foundation/Foundation.h>

@class Reachability;

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

@property BOOL internetActive;
@property BOOL hostActive;

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

@end

Und die .m-Datei:

#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

Jemand has hat dieses Problem auf einfache, wiederverwendbare Weise gelöst. DDGReachability .

BEARBEITEN: Oder tonymillion/Reachability .

6
darvids0n

Ich extrahierte den Code und stellte ihn in eine einzige Methode. Ich hoffe, er würde anderen helfen.

#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

Ich denke das könnte helfen ..

[[AFNetworkReachabilityManager sharedManager] startMonitoring];

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

Sie können dieses auch versuchen, wenn Sie AFNetworking bereits in Ihrem Projekt konfiguriert haben. 

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

Ich schreibe die Swift-Version der akzeptierten Antwort hier , falls jemand es für nützlich hält, wird der Code Swift 2 geschrieben. 

Sie können die erforderlichen Dateien von SampleCode herunterladen.

Fügen Sie Ihrem Projekt Reachability.h und Reachability.m-Datei hinzu.

Jetzt muss eine Bridging-Header.h-Datei erstellt werden, wenn keine für Ihr Projekt vorhanden ist. 

Fügen Sie in Ihrer Bridging-Header.h-Datei folgende Zeile hinzu:

#import "Reachability.h"

Jetzt, um nach Internetverbindung zu suchen 

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
    }

}
2
Satyen Udeshi

Hier ist eine gute Lösung für die Überprüfung der Konnektivität mit Swift ohne Verwendung der Reichweite. Ich habe es auf diesem Blog gefunden.

Erstellen Sie in Ihrem Projekt eine neue Swift-Datei mit dem Namen Network.Swift (zum Beispiel). Fügen Sie diesen Code in diese Datei ein:

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

Sie können dann an beliebigen Stellen in Ihrem Projekt nach Verbindungen suchen, indem Sie Folgendes verwenden:

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

EDIT: Dies funktioniert nicht für Netzwerk-URLs (siehe Kommentare)

Ab iOS 5 gibt es eine neue NSURL-Instanzmethode: 

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

Zeigen Sie auf die Website, die Sie interessiert, oder auf Apple.com. Ich denke, es ist der neue einzeilige Anruf, um zu sehen, ob das Internet auf Ihrem Gerät funktioniert.

0
SG1

Ersatz für Apples Reachability in Swift mit Verschlüssen, inspiriert von Tonymillion: https://github.com/ashleymills/Reachability.Swift

  1. Legen Sie die Datei Reachability.Swift in Ihr Projekt ab. Verwenden Sie alternativ CocoaPods oder Carthage -. Siehe Abschnitt Installation der README des Projekts.

  2. Erhalten Sie Benachrichtigungen über die Netzwerkverbindung:

    //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")
    }
    

    und zum Stoppen von Benachrichtigungen

    reachability.stopNotifier()
    
0
Pierre F

Ich war auch nicht zufrieden mit den verfügbaren Internet-Überprüfungsoptionen (Warum ist dies keine native API?!?!) 

Mein eigenes Problem war mit 100% Paketverlust - wenn ein Gerät an den Router angeschlossen ist, der Router jedoch nicht mit dem Internet verbunden ist. Erreichbarkeit und andere werden ewig hängen. Ich habe eine Utility-Singleton-Klasse erstellt, um damit umzugehen, indem ein asynchrones Timeout hinzugefügt wurde. Es funktioniert gut in meiner App. Ich hoffe es hilft. Hier ist der Link zu Github: 

https://github.com/fareast555/TFInternetChecker

0
Mike Critchley

Überprüfen der Verfügbarkeit der Internetverbindung in (iOS) Xcode 8.2, Swift 3.0  

Dies ist eine einfache Methode zur Überprüfung der Netzwerkverfügbarkeit. Ich habe es geschafft, es in Swift 2.0 und hier den endgültigen Code zu übersetzen. Die vorhandene Apple Reachability-Klasse und andere Bibliotheken von Drittanbietern schienen zu kompliziert zu sein, um sie in Swift zu übersetzen.

Dies funktioniert sowohl für 3G- als auch für WLAN-Verbindungen.

Vergessen Sie nicht, "SystemConfiguration.framework" zu Ihrem Projektersteller hinzuzufügen.

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

Alamofire

Wenn Sie bereits Alamofire für alle RESTful Api verwenden, können Sie davon profitieren.

Sie können Ihrer App die folgende Klasse hinzufügen und MNNetworkUtils.main.isConnected() aufrufen, um ein boolesches Verhalten darüber zu erhalten, ob eine Verbindung besteht oder nicht.

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

Dies ist eine Einzelklasse. Jedes Mal, wenn der Benutzer das Netzwerk verbindet oder trennt, überschreibt er self.reachable korrekt in true/false, da wir bei der Initialisierung des Singleton die NetworkReachabilityManager-Einstellung abhören.

Um die Erreichbarkeit zu überwachen, müssen Sie einen Host angeben. Zur Zeit verwende ich google.com. Sie können bei Bedarf zu einem anderen Host oder einem Ihrer Hosts wechseln.

0
nuynait