Je sais que cette question semblera être une dupe de nombreuses autres, mais je ne pense pas que le cas simple soit bien expliqué ici. Venant des environnements Android et BlackBerry, les demandes via HTTPUrlConnection
échouent instantanément si aucune connexion n'est disponible. Cela semble être un comportement complètement sain d'esprit et j'ai été surpris de constater que NSURLConnection
dans iOS ne l'imitait pas.
Je comprends que Apple (et d’autres qui l’ont étendue) fournit une classe Reachability
pour aider à déterminer l’état du réseau. J'étais heureux de voir ceci en premier et je m'attendais vraiment à voir quelque chose comme bool isNetworkAvailable()
, mais à ma grande surprise, j'ai trouvé un système complexe nécessitant des enregistrements de notifications et des rappels, ainsi que des détails apparemment inutiles. Il doit y avoir un meilleur moyen.
Mon application gère déjà avec élégance les échecs de connexion, y compris l'absence de connectivité. L'utilisateur est informé de l'échec et l'application continue.
Ainsi, mes exigences sont simples: Fonction unique et synchrone que je peux appeler avant toutes les demandes HTTP pour déterminer si je devrais me donner la peine d’envoyer réellement la demande ou non. Idéalement, il ne nécessite aucune configuration et renvoie simplement un booléen.
Est-ce vraiment pas possible sur iOS?
J'ai fait un peu plus de recherches et je mets à jour ma réponse avec une solution plus récente. Je ne sais pas si vous l'avez déjà consulté, mais Apple fournit un exemple de code intéressant.
Téléchargez l'exemple de code ici
Incluez les fichiers Reachability.h et Reachability.m dans votre projet. Jetez un coup d’œil à ReachabilityAppDelegate.m pour voir un exemple sur la façon de déterminer l’atteignabilité de l’hôte, celle-ci par WiFi, par WWAN, etc. Pour une vérification très simple de l’accessibilité au réseau, procédez comme suit:
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: N'oubliez pas d'ajouter SystemConfiguration.framework à votre projet.
Considérant que ce fil est le premier résultat de Google pour ce type de question, je me suis dit que je fournirais la solution qui fonctionnerait pour moi. J'utilisais déjà AFNetworking , mais la recherche n'a pas révélé comment accomplir cette tâche avec AFNetworking jusqu'à la moitié de mon projet.
Ce que vous voulez, c'est le 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;
}
}];
Vous pouvez également utiliser les éléments suivants pour tester l'accessibilité de manière synchrone (une fois la surveillance démarrée):
-(BOOL) isInternetReachable
{
return [AFNetworkReachabilityManager sharedManager].reachable;
}
Désolé de répondre trop tard, mais j'espère que cette réponse pourra aider quelqu'un à l'avenir.
Voici un petit extrait de code C natif qui permet de vérifier la connectivité Internet sans aucune classe supplémentaire.
Ajoutez les en-têtes suivants:
#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
}
J'utilise actuellement cette méthode synchrone simple qui ne nécessite aucun fichier supplémentaire dans vos projets ou vos délégués.
Importation:
#import <SystemConfiguration/SCNetworkReachability.h>
Créez cette méthode:
+(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;
}
Ensuite, si vous avez mis ceci dans une MyNetworkClass
:
if( [MyNetworkClass isNetworkAvailable] )
{
// do something networky.
}
Si vous testez dans le simulateur, activez et désactivez le Wi-Fi de votre Mac, car il semble que le simulateur ignore les paramètres du téléphone.
Mettre à jour:
En fin de compte, j'ai utilisé un rappel thread/asynchrone pour éviter de bloquer le thread principal; et testez régulièrement pour que je puisse utiliser un résultat mis en cache, même si vous devez éviter de garder inutilement des connexions de données ouvertes.
Comme @thunk l'a décrit, il existe de meilleures URL à utiliser, qu'Apple utilise elle-même. http://cadinc.com/blog/why-your-Apple-ios-7-device-wont-connect-to-the-wifi-network
C’est possible et c’est très simple si vous le regardez à la fin de la mise en œuvre, ce qui est à nouveau - très simple, puisque vous n’avez besoin que de deux variables booléennes: accessibilité Internet et accessibilité hôte (vous avez souvent besoin de plus d’une ). Une fois que vous avez assemblé votre classe d'assistance capable de déterminer l'état des connexions, vous ne vous souciez plus de l'implémentation nécessaire pour connaître ces procédures.
Exemple:
#import <Foundation/Foundation.h>
@class Reachability;
@interface ConnectionManager : NSObject {
Reachability *internetReachable;
Reachability *hostReachable;
}
@property BOOL internetActive;
@property BOOL hostActive;
- (void) checkNetworkStatus:(NSNotification *)notice;
@end
Et le fichier .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
Quelqu'un a résolu ce problème de manière simple et réutilisable auparavant. DDGReachability
.
EDIT: Ou tonymillion/Reachability
.
J'ai extrait le code et mis en une seule méthode, espérant que cela aiderait les autres.
#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;
}
Je pense que cela pourrait aider ..
[[AFNetworkReachabilityManager sharedManager] startMonitoring];
if([AFNetworkReachabilityManager sharedManager].isReachable)
{
NSLog(@"Network reachable");
}
else
{
NSLog(@"Network not reachable");
}
Vous pouvez également essayer celui-ci si vous avez déjà configuré AFNetworking dans votre projet.
-(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;
}
}
J'écris la version Swift de la réponse acceptée ici , si quelqu'un la trouve utile, le code est écrit Swift 2,
Vous pouvez télécharger les fichiers requis depuis SampleCode
Ajoutez le fichier Reachability.h
et Reachability.m
à votre projet,
Maintenant, il faudra créer un fichier Bridging-Header.h
s'il n'en existe aucun pour votre projet,
Dans votre fichier Bridging-Header.h
, ajoutez cette ligne:
#import "Reachability.h"
Maintenant, afin de vérifier la connexion Internet
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
}
}
Voici une bonne solution pour vérifier la connectivité à l'aide de Swift, sans utiliser l'accessibilité. Je l'ai trouvé sur ce blog .
Créez un nouveau fichier Swift dans votre projet appelé Network.Swift
(par exemple). Collez ce code dans ce fichier:
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
}
}
Vous pouvez ensuite vérifier la connectivité n'importe où dans votre projet en utilisant:
if Network.isConnectedToNetwork() == true {
println("Internet connection OK")
} else {
println("Internet connection FAILED")
}
EDIT: Cela ne fonctionnera pas pour les URL du réseau (voir les commentaires)
Depuis iOS 5, il existe une nouvelle méthode d'instance NSURL:
- (BOOL)checkResourceIsReachableAndReturnError:(NSError **)error
Pointez-le sur le site Web qui vous tient à cœur ou sur Apple.com; Je pense que c'est le nouvel appel d'une ligne pour voir si Internet fonctionne sur votre appareil.
Remplacement de la version de Reachability d'Apple dans Swift avec des fermetures, inspirée de tonymillion: https://github.com/ashleymills/Reachability.Swift
Déposez le fichier Reachability.Swift
dans votre projet. Vous pouvez également utiliser CocoaPods ou Carthage - Voir la section Installation du fichier README du projet.
Recevez des notifications sur la connectivité réseau:
//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")
}
et pour arrêter les notifications
reachability.stopNotifier()
Je n’étais pas non plus satisfait des options de vérification Internet disponibles (pourquoi n’est-ce pas une API native?!?!)
Mon propre problème était avec 100% de perte de paquets - lorsqu'un périphérique est connecté au routeur, mais que le routeur n'est pas connecté à Internet. L'accessibilité et d'autres vont durer pendant des siècles. J'ai créé une classe d'utilitaires singleton pour y remédier en ajoutant un délai d'attente asynchrone. Cela fonctionne bien dans mon application. J'espère que ça aide. Voici le lien sur github:
Vérification de la disponibilité de la connexion Internet dans (iOS) Xcode 8.2, Swift 3.0
C'est une méthode simple pour vérifier la disponibilité du réseau. J'ai réussi à le traduire en Swift 2.0 et voici le code final . La classe Apple Reachability existante et les bibliothèques tierces semblaient trop compliquées pour être traduites en Swift.
Cela fonctionne pour les connexions 3G et WiFi.
N’oubliez pas d’ajouter «SystemConfiguration.framework» à votre constructeur de projet.
//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")
}
Si vous utilisez déjà Alamofire pour tous les Api RESTful, voici ce que vous pouvez en tirer.
Vous pouvez ajouter la classe suivante à votre application et appeler MNNetworkUtils.main.isConnected()
pour obtenir un booléen indiquant si elle est connectée ou non.
#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
}
}
Ceci est une classe singleton. Chaque fois que l'utilisateur connecte ou déconnecte le réseau, il remplace self.reachable
par true/false correctement, car nous commençons à écouter NetworkReachabilityManager
lors de l'initialisation du singleton.
Aussi, afin de contrôler l'accessibilité, vous devez fournir un hôte. Actuellement, j'utilise google.com
. N'hésitez pas à changer pour tout autre hôte ou l'un des vôtres si nécessaire.