Самый простой способ обнаружить подключение к Интернету в iOS?

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

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

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

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

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

Ответы

Ответ 1

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

Ответ 2

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

Извините за ответ слишком поздно, но я надеюсь, что этот ответ может помочь кому-то в будущем.

Ниже приведен небольшой фрагмент кода 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
    }

Ответ 4

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

Импорт

#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, так как, похоже, симулятор игнорирует настройки телефона.

Update:

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

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

Ответ 5

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

Пример:

#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

Ответ 7

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

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


}

Ответ 8

Я думаю, что это могло бы помочь.

[[AFNetworkReachabilityManager sharedManager] startMonitoring];

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

Ответ 9

Я пишу быструю версию принятого ответа здесь, если кто-то сочтет это полезным, код написан 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
    }

}

Ответ 10

Вот хорошее решение для проверки возможности подключения с помощью 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")
}

Ответ 11

Проверка доступности интернет-соединения в (iOS) Xcode 8.2, Swift 3.0

Это простой способ проверки доступности сети. Мне удалось перевести его в Swift 2.0, а здесь - окончательный код. Существующий класс Apple Reachability и другие сторонние библиотеки казались слишком сложными для перевода на Swift.

Это работает как для 3G, так и для Wi-Fi-соединений.

Не забудьте добавить "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")
}

Ответ 12

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

Ответ 13

EDIT: это не будет работать для сетевых URL (см. комментарии)

Как и в iOS 5, существует новый метод экземпляра NSURL:

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

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

Ответ 14

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

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

https://github.com/fareast555/TFInternetChecker

Ответ 15

Замена для Apple Reachability переписана в Swift с закрытием, вдохновленная tonymillion: https://github.com/ashleymills/Reachability.swift

  • Отбросьте файл Reachability.swift в свой проект. В качестве альтернативы используйте CocoaPods или Carthage - См. Раздел "Установка" проекта README.

  • Получить уведомления о подключении к сети:

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