it-swarm.com.ru

Самый простой способ обнаружить интернет-соединение на iOS?

Я знаю, что этот вопрос окажется обманом для многих других, однако я не чувствую, что простой случай хорошо объяснен здесь. Исходя из Android и BlackBerry, отправка запросов через HTTPUrlConnection мгновенно завершается неудачей, если нет доступного соединения. Это похоже на вполне нормальное поведение, и я был удивлен, обнаружив, что NSURLConnection в iOS не эмулирует его.

Я понимаю, что Apple (и другие, кто ее расширил) предоставляют класс Reachability для определения состояния сети. Я был счастлив сначала увидеть это и ожидал увидеть что-то вроде bool isNetworkAvailable(), но вместо этого к своему удивлению я обнаружил сложную систему, требующую регистрации уведомлений и обратных вызовов, и кучу, казалось бы, ненужных деталей. Должен быть лучший способ.

Мое приложение уже корректно обрабатывает сбои подключения, в том числе отсутствие подключения. Пользователь получает уведомление о сбое, и приложение продолжает работу.

Таким образом, мои требования просты: одиночная синхронная функция, которую я могу вызвать перед всеми HTTP-запросами, чтобы определить, стоит ли мне беспокоить фактическую отправку запроса или нет. В идеале он не требует настройки и просто возвращает логическое значение.

Это действительно невозможно на iOS?

143
RealCasually

Я провел немного больше исследований и обновляю свой ответ более актуальным решением. Я не уверен, что вы уже посмотрели его, но есть пример кода Nice от Apple. 

Загрузите образец кода здесь

Включите файлы 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
Semere Taézaz Sium

Учитывая, что эта тема является лучшим результатом поиска 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 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

В настоящее время я использую этот простой синхронный метод, который не требует дополнительных файлов в ваших проектах или делегатах.

Импортировать:

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

Если вы тестируете в симуляторе, включите и выключите Wi-Fi на вашем Mac, так как кажется, что симулятор проигнорирует настройки телефона.

Обновление:

  1. В конце я использовал поток/асинхронный обратный вызов, чтобы избежать блокировки основного потока; и регулярно повторять тестирование, чтобы я мог использовать кэшированный результат - хотя вы должны избегать ненужного открытия соединений с данными.

  2. Как описал @thunk, есть лучшие URL-адреса для использования, которые используют сами Apple. http://cadinc.com/blog/why-your-Apple-ios-7-device-wont-connect-to-the-wifi-network

31
GilesDMiddleton

Это возможно, и это действительно просто, если вы посмотрите на это после завершения реализации, что опять-таки очень просто, поскольку вам нужны только две логические переменные: доступность интернета и доступность хоста (вам часто требуется более одной из этих ). После того, как вы соберете свой вспомогательный класс, который может определять состояние соединений, вам больше не нужно заботиться о реализации, необходимой для знания этих процедур.

Пример:

#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

Кто-то имеет решил эту проблему простым и многократно используемым способом. DDGReachability .

Правка: Или tonymillion/Reachability .

6
darvids0n

Я извлек код и поместил в один метод, надеюсь, он поможет другим.

#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

Вы также можете попробовать это, если вы уже настроили 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
Ravi Raja Jangid

Я пишу 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
    }

}
2
Satyen Udeshi

Вот хорошее решение для проверки подключения с использованием Swift, без использования Reachability. Я нашел это в этом блоге .

Создайте новый файл Swift в своем проекте с именем Network.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

Направьте его на интересующий вас сайт или укажите на Apple.com; Я думаю, что это новый однострочный звонок, чтобы увидеть, работает ли интернет на вашем устройстве.

0
SG1

Замена для Reachability от Apple переписана в Swift с замыканиями, вдохновленными tonymillion: 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
Pierre F

Я также не был доволен доступными опциями проверки интернета (почему это не нативный API?!?!) 

Моя собственная проблема была со 100% потерей пакетов - когда устройство подключено к маршрутизатору, но маршрутизатор не подключен к Интернету. Достижимость и другие будут зависать целую вечность. Я создал вспомогательный одноэлементный класс, чтобы справиться с этим, добавив время ожидания асинхронности. Это прекрасно работает в моем приложении. Надеюсь, поможет. Вот ссылка на github: 

https://github.com/fareast555/TFInternetChecker

0
Mike Critchley

Проверка доступности интернет-соединения в (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")
}
0
ViJay Avhad

Alamofire

Если вы уже используете Alamofire для всех RESTful Api, вот что вы можете извлечь из этого.

Вы можете добавить следующий класс в свое приложение и вызвать 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, если хотите, смените его на любой другой хост или один из ваших.

0
nuynait