在 iOS 上检测互联网连接最简单的方法是什么?

我知道这个问题似乎是许多其他人的欺骗,然而,我不觉得这个简单的情况是很好的解释这里。来自 Android 和黑莓的后台,如果没有可用的连接,通过 HTTPUrlConnection发出的请求会立即失败。这似乎是完全正常的行为,我很惊讶地发现,iOS 中的 NSURLConnection没有模仿它。

我知道苹果公司(和其他已经扩展它的公司)提供了一个 Reachability类来帮助确定网络状态。我很高兴第一次看到这个,并完全期待看到类似于 bool isNetworkAvailable()的东西,但令我惊讶的是,我发现了一个复杂的系统,需要通知注册和回调,以及一堆似乎不必要的细节。一定有更好的办法。

我的应用程序已经能够很好地处理连接故障,包括没有连接。用户被通知失败,应用程序继续前进。

因此,我的要求很简单: 我可以在所有 HTTP 请求之前调用单个同步函数,以确定是否需要实际发送请求。理想情况下,它不需要设置,只需返回一个布尔值。

这在 iOS 上真的不可能吗?

142562 次浏览

这是可能的,如果你在完成实现的时候看一下,就会发现它真的很简单,同样非常简单,因为你需要的只是两个布尔变量: 互联网可达性和主机可达性(你通常需要不止一个这样的变量)。一旦组装了可以确定连接状态的帮助器类,就不再关心了解这些过程所需的实现。

例如:

#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

我做了更多的研究,我正在更新我的答案,一个更新的解决方案。我不确定你是否已经看过了,但是苹果提供了一个很好的示例代码。

下载示例代码 给你

在您的项目中包含 Reachabity.h 和 Reachabity.m 文件。看一下 ReachabityAppgenerate.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");
}

@ Benjamin Piette’s: 不要忘记在项目中添加 SystemConfiguration.Framework。

以前有人用一种简单的、可重用的方法解决了这个问题。

编辑: 或 tonymillion/Reachability

编辑: 这不适用于网络 URL (见注释)

在 iOS5中,有一个新的 NSURL 实例方法:

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

把它指向你关心的网站,或指向 apple.com; 我认为这是一个新的一线电话,看看互联网是否在你的设备上工作。

我把代码提取出来,放到一个单独的方法里,希望能对其他人有所帮助。

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




}

很抱歉回复的太晚,但我希望这个答案可以帮助某人在未来。

下面是一个小的原生 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
}

看到这个线程是顶部的谷歌结果为这种类型的问题,我想我会提供的解决方案,为我工作。我已经在使用 AFNetworking了,但是直到我的项目进行到一半的时候,搜索才揭示了如何使用 AFNetworking 来完成这个任务。

你想要的是 AFNetworkingReachabityManager .

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

我目前使用这个简单的同步方法,在您的项目或委托中不需要额外的文件。

进口:

#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 所描述的,有更好的 URL 可以使用,苹果自己也使用

这里有一个很好的解决方案来检查连接使用 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")
}

我也不喜欢可用的 Internet 检查选项(为什么这不是一个本地 API? !)

我自己的问题是100% 的数据包丢失——当一个设备连接到路由器,但路由器没有连接到互联网。可达性和其他因素将长期悬而未决。我创建了一个实用的单例类,通过添加一个异步超时来处理这个问题。它在我的应用程序中运行良好。希望能有帮助。下面是 github 上的链接:

Https://github.com/fareast555/tfinternetchecker

我觉得这可以帮助. 。

[[AFNetworkReachabilityManager sharedManager] startMonitoring];


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

我写的快速版本的公认答案 给你,如果有人认为它有用,代码是写迅速2,

您可以从 样本代码下载所需的文件

Reachability.hReachability.m文件添加到项目中,

现在,如果您的项目中不存在 Bridging-Header.h文件,则需要创建 Bridging-Header.h文件,

Bridging-Header.h文件中添加以下代码行:

#import "Reachability.h"

现在为了检查 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
}


}

在(iOS) Xcode 8.2,Swift 3.0中检查 Internet 连接可用性

这是检查网络可用性的简单方法。 我把它翻译成了 Swift 2.0这是最终代码。 现有的 Apple Reacability 类和其他第三方库似乎过于复杂,无法翻译成 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")
}

如果您已经在项目中配置了 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;
}
}

取代苹果的可达性重写 有闭包的 Swift,灵感来自 tonymillion: https://github.com/ashleymills/Reachability.swift

  1. 将文件 Reachability.swift拖放到项目中。或者,使用 可可豆迦太基-参见项目的 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()
    

Alamofire

如果您已经在所有 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
}
}

这是一个单件类。每次当用户连接或断开网络时,它都会正确地将 self.reachable覆盖为 true/false,因为我们开始在单例初始化时监听 NetworkReachabilityManager

另外,为了监测可达性,您需要提供一个主机,目前我正在使用 google.com随时更改到任何其他主机或您的一个,如果需要的话。