我的百度翻译只能使用无线网数据包收到0不能使用蜂窝数据,为什么?

I'm working on an iPhone app and I'd like to be able to check if the phone is able to make phone calls (and warn the user if not).
This could be due to no cellular service being available or if the user has placed the phone in "airplane mode".
I've looked around Apple's docs and I can't find anything that would let me check this.
Am I missing something, or does Apple not expose this information to apps?
EDIT: Just to emphasize, I'm not interested in checking for an IP network connection, but would like to determine if my app can make a phone call.
解决方案 Look at reachability.m. Although I'm not positive about cell signal strength, if something similar exists, it would be contained in this file.
Here's an example of how to use it to detect network reachability:
Reachability.m:
===== IMPORTANT =====
This is sample code demonstrating API, technology or techniques in development.
Although this sample code has been reviewed for technical accuracy, it is not
final. Apple is supplying this information to help you plan for the adoption of
the technologies and programming interfaces described herein. This information
is subject to change, and software implemented based on this sample code should
be tested with final operating system software and final documentation. Newer
versions of this sample code may be provided with future seeds of the API or
technology. For information about updates to this and other developer
documentation, view the New & Updated sidebars in subsequent documentation
=====================
File: Reachability.m
Abstract: SystemConfiguration framework wrapper.
Version: 1.4
Disclaimer: IMPORTANT:
This Apple software is supplied to you by Apple Inc.
("Apple") in consideration of your agreement to the following terms, and your
use, installation, modification or redistribution of this Apple software
constitutes acceptance of these terms.
If you do not agree with these terms,
please do not use, install, modify or redistribute this Apple software.
In consideration of your agreement to abide by the following terms, and subject
to these terms, Apple grants you a personal, non-exclusive license, under
Apple's copyrights in this original Apple software (the "Apple Software"), to
use, reproduce, modify and redistribute the Apple Software, with or without
modifications, in source and/ provided that if you redistribute
the Apple Software in its entirety and without modifications, you must retain
this notice and the following text and disclaimers in all such redistributions
of the Apple Software.
Neither the name, trademarks, service marks or logos of Apple Inc. may be used
to endorse or promote products derived from the Apple Software without specific
prior written permission from Apple.
Except as expressly stated in this notice,
no other rights or licenses, express or implied, are granted by Apple herein,
including but not limited to any patent rights that may be infringed by your
derivative works or by other works in which the Apple Software may be
incorporated.
The Apple Software is provided by Apple on an "AS IS" basis.
APPLE MAKES NO
WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
COMBINATION WITH YOUR PRODUCTS.
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR
DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF
CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF
APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Copyright (C) 2008 Apple Inc. All Rights Reserved.
#import &sys/socket.h&
#import &netinet/in.h&
#import &netinet6/in6.h&
#import &arpa/inet.h&
#import &ifaddrs.h&
#include &netdb.h&
#import "Reachability.h"
#import &SystemConfiguration/SCNetworkReachability.h&
static NSString *kLinkLocalAddressKey = @"169.254.0.0";
static NSString *kDefaultRouteKey = @"0.0.0.0";
static Reachability *_sharedR
// A class extension that declares internal methods for this class.
@interface Reachability()
- (BOOL)isAdHocWiFiNetworkAvailableFlags:(SCNetworkReachabilityFlags *)outF
- (BOOL)isNetworkAvailableFlags:(SCNetworkReachabilityFlags *)outF
- (BOOL)isReachableWithoutRequiringConnection:(SCNetworkReachabilityFlags)
- (SCNetworkReachabilityRef)reachabilityRefForHostName:(NSString *)hostN
- (SCNetworkReachabilityRef)reachabilityRefForAddress:(NSString *)
- (BOOL)addressFromString:(NSString *)IPAddress address:(struct sockaddr_in *)outA
- (void)stopListeningForReachabilityC
@implementation Reachability
@synthesize networkStatusNotificationsEnabled = _networkStatusNotificationsE
@synthesize hostName = _hostN
@synthesize address = _
@synthesize reachabilityQueries = _reachabilityQ
+ (Reachability *)sharedReachability
if (!_sharedReachability) {
_sharedReachability = [[Reachability alloc] init];
// Clients of Reachability will typically call [[Reachability sharedReachability] setHostName:]
// before calling one of the status methods.
_sharedReachability.hostName =
_sharedReachability.address =
_sharedReachability.networkStatusNotificationsEnabled = NO;
_sharedReachability.reachabilityQueries = [[NSMutableDictionary alloc] init];
return _sharedR
- (void) dealloc
[self stopListeningForReachabilityChanges];
[_sharedReachability.reachabilityQueries release];
[_sharedReachability release];
[super dealloc];
- (BOOL)isReachableWithoutRequiringConnection:(SCNetworkReachabilityFlags)flags
// kSCNetworkReachabilityFlagsReachable indicates that the specified nodename or address can
// be reached using the current network configuration.
BOOL isReachable = flags & kSCNetworkReachabilityFlagsR
// This flag indicates that the specified nodename or address can
// be reached using the current network configuration, but a
// connection must first be established.
// As an example, this status would be returned for a dialup
// connection that was not currently active, but could handle
// network traffic for the target system.
// If the flag is false, we don't have a connection. But because CFNetwork
// automatically attempts to bring up a WWAN connection, if the WWAN reachability
// flag is present, a connection is not required.
BOOL noConnectionRequired = !(flags & kSCNetworkReachabilityFlagsConnectionRequired);
if ((flags & kSCNetworkReachabilityFlagsIsWWAN)) {
noConnectionRequired = YES;
return (isReachable && noConnectionRequired) ? YES : NO;
// Returns whether or not the current host name is reachable with the current network configuration.
- (BOOL)isHostReachable:(NSString *)host
if (!host || ![host length]) {
return NO;
SCNetworkReachabilityF
SCNetworkReachabilityRef reachability =
SCNetworkReachabilityCreateWithName(NULL, [host UTF8String]);
BOOL gotFlags = SCNetworkReachabilityGetFlags(reachability, &flags);
CFRelease(reachability);
if (!gotFlags) {
return NO;
return [self isReachableWithoutRequiringConnection:flags];
// This returns YES if the address 169.254.0.0 is reachable without requiring a connection.
- (BOOL)isAdHocWiFiNetworkAvailableFlags:(SCNetworkReachabilityFlags *)outFlags
// Look in the cache of reachability queries for one that matches this query.
ReachabilityQuery *query = [self.reachabilityQueries objectForKey:kLinkLocalAddressKey];
SCNetworkReachabilityRef adHocWiFiNetworkReachability = query.reachabilityR
// If a cached reachability query was not found, create one.
if (!adHocWiFiNetworkReachability) {
// Build a sockaddr_in that we can pass to the address reachability query.
struct sockaddr_
bzero(&sin, sizeof(sin));
sin.sin_len = sizeof(sin);
sin.sin_family = AF_INET;
// IN_LINKLOCALNETNUM is defined in &netinet/in.h& as 169.254.0.0
sin.sin_addr.s_addr = htonl(IN_LINKLOCALNETNUM);
adHocWiFiNetworkReachability = SCNetworkReachabilityCreateWithAddress(NULL, (struct sockaddr *)&sin);
query = [[[ReachabilityQuery alloc] init] autorelease];
query.hostNameOrAddress = kLinkLocalAddressK
query.reachabilityRef = adHocWiFiNetworkR
// Add the reachability query to the cache.
[self.reachabilityQueries setObject:query forKey:kLinkLocalAddressKey];
// If necessary, register for notifcations for the SCNetworkReachabilityRef on the current run loop.
// If an existing SCNetworkReachabilityRef was found in the cache, we can reuse it and register
// to receive notifications from it in the current run loop, which may be different than the run loop
// that was previously used when registering the SCNetworkReachabilityRef for notifications.
// -scheduleOnRunLoop: will schedule only if network status notifications are enabled in the Reachability instance.
// By default, they are not enabled.
[query scheduleOnRunLoop:[NSRunLoop currentRunLoop]];
SCNetworkReachabilityFlags addressReachabilityF
BOOL gotFlags = SCNetworkReachabilityGetFlags(adHocWiFiNetworkReachability, &addressReachabilityFlags);
if (!gotFlags) {
// There was an error getting the reachability flags.
return NO;
// Callers of this method might want to use the reachability flags, so if an 'out' parameter
// was passed in, assign the reachability flags to it.
if (outFlags) {
*outFlags = addressReachabilityF
return [self isReachableWithoutRequiringConnection:addressReachabilityFlags];
// ReachabilityCallback is registered as the callback for network state changes in startListeningForReachabilityChanges.
static void ReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void *info)
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// Post a notification to notify the client that the network reachability changed.
[[NSNotificationCenter defaultCenter] postNotificationName:@"kNetworkReachabilityChangedNotification" object:nil];
[pool release];
// Perform a reachability query for the address 0.0.0.0. If that address is reachable without
// requiring a connection, a network interface is available. We'll have to do more work to
// determine which network interface is available.
- (BOOL)isNetworkAvailableFlags:(SCNetworkReachabilityFlags *)outFlags
ReachabilityQuery *query = [self.reachabilityQueries objectForKey:kDefaultRouteKey];
SCNetworkReachabilityRef defaultRouteReachability = query.reachabilityR
if (!defaultRouteReachability) {
struct sockaddr_in zeroA
bzero(&zeroAddress, sizeof(zeroAddress));
zeroAddress.sin_len = sizeof(zeroAddress);
zeroAddress.sin_family = AF_INET;
defaultRouteReachability = SCNetworkReachabilityCreateWithAddress(NULL, (struct sockaddr *)&zeroAddress);
ReachabilityQuery *query = [[[ReachabilityQuery alloc] init] autorelease];
query.hostNameOrAddress = kDefaultRouteK
query.reachabilityRef = defaultRouteR
[self.reachabilityQueries setObject:query forKey:kDefaultRouteKey];
// If necessary, register for notifcations for the SCNetworkReachabilityRef on the current run loop.
// If an existing SCNetworkReachabilityRef was found in the cache, we can reuse it and register
// to receive notifications from it in the current run loop, which may be different than the run loop
// that was previously used when registering the SCNetworkReachabilityRef for notifications.
// -scheduleOnRunLoop: will schedule only if network status notifications are enabled in the Reachability instance.
// By default, they are not enabled.
[query scheduleOnRunLoop:[NSRunLoop currentRunLoop]];
SCNetworkReachabilityF
BOOL gotFlags = SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags);
if (!gotFlags) {
return NO;
BOOL isReachable = [self isReachableWithoutRequiringConnection:flags];
// Callers of this method might want to use the reachability flags, so if an 'out' parameter
// was passed in, assign the reachability flags to it.
if (outFlags) {
*outFlags =
return isR
// Be a good citizen an unregister for network state changes when the application terminates.
- (void)stopListeningForReachabilityChanges
// Walk through the cache that holds SCNetworkReachabilityRefs for reachability
// queries to particular hosts or addresses.
NSEnumerator *enumerator = [self.reachabilityQueries objectEnumerator];
ReachabilityQuery *reachabilityQ
while (reachabilityQuery = [enumerator nextObject]) {
CFArrayRef runLoops = reachabilityQuery.runL
NSUInteger runLoopCounter, maxRunLoops = CFArrayGetCount(runLoops);
for (runLoopCounter = 0; runLoopCounter & maxRunL runLoopCounter++) {
CFRunLoopRef nextRunLoop = (CFRunLoopRef)CFArrayGetValueAtIndex(runLoops, runLoopCounter);
SCNetworkReachabilityUnscheduleFromRunLoop(reachabilityQuery.reachabilityRef, nextRunLoop, kCFRunLoopDefaultMode);
CFArrayRemoveAllValues(reachabilityQuery.runLoops);
Create a SCNetworkReachabilityRef for hostName, which lets us determine if hostName
is currently reachable, and lets us register to receive notifications when the
reachability of hostName changes.
- (SCNetworkReachabilityRef)reachabilityRefForHostName:(NSString *)hostName
if (!hostName || ![hostName length]) {
return NULL;
// Look in the cache for an existing SCNetworkReachabilityRef for hostName.
ReachabilityQuery *cachedQuery = [self.reachabilityQueries objectForKey:hostName];
SCNetworkReachabilityRef reachabilityRefForHostName = cachedQuery.reachabilityR
if (reachabilityRefForHostName) {
return reachabilityRefForHostN
// Didn't find an existing SCNetworkReachabilityRef for hostName, so create one ...
reachabilityRefForHostName = SCNetworkReachabilityCreateWithName(kCFAllocatorDefault, [hostName UTF8String]);
NSAssert1(reachabilityRefForHostName != NULL, @"Failed to create SCNetworkReachabilityRef for host: %@", hostName);
ReachabilityQuery *query = [[[ReachabilityQuery alloc] init] autorelease];
query.hostNameOrAddress = hostN
query.reachabilityRef = reachabilityRefForHostN
// If necessary, register for notifcations for the SCNetworkReachabilityRef on the current run loop.
// If an existing SCNetworkReachabilityRef was found in the cache, we can reuse it and register
// to receive notifications from it in the current run loop, which may be different than the run loop
// that was previously used when registering the SCNetworkReachabilityRef for notifications.
// -scheduleOnRunLoop: will schedule only if network status notifications are enabled in the Reachability instance.
// By default, they are not enabled.
[query scheduleOnRunLoop:[NSRunLoop currentRunLoop]];
// ... and add it to the cache.
[self.reachabilityQueries setObject:query forKey:hostName];
return reachabilityRefForHostN
Create a SCNetworkReachabilityRef for the IP address in addressString, which lets us determine if
the address is currently reachable, and lets us register to receive notifications when the
reachability of the address changes.
- (SCNetworkReachabilityRef)reachabilityRefForAddress:(NSString *)addressString
if (!addressString || ![addressString length]) {
return NULL;
struct sockaddr_
BOOL gotAddress = [self addressFromString:addressString address:&address];
// The attempt to convert addressString to a sockaddr_in failed.
if (!gotAddress) {
NSAssert1(gotAddress != NO, @"Failed to convert an IP address string to a sockaddr_in: %@", addressString);
return NULL;
// Look in the cache for an existing SCNetworkReachabilityRef for addressString.
ReachabilityQuery *cachedQuery = [self.reachabilityQueries objectForKey:addressString];
SCNetworkReachabilityRef reachabilityRefForAddress = cachedQuery.reachabilityR
if (reachabilityRefForAddress) {
return reachabilityRefForA
// Didn't find an existing SCNetworkReachabilityRef for addressString, so create one ...
reachabilityRefForAddress = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (struct sockaddr *)&address);
NSAssert1(reachabilityRefForAddress != NULL, @"Failed to create SCNetworkReachabilityRef for address: %@", addressString);
ReachabilityQuery *query = [[[ReachabilityQuery alloc] init] autorelease];
query.hostNameOrAddress = addressS
query.reachabilityRef = reachabilityRefForA
// If necessary, register for notifcations for the SCNetworkReachabilityRef on the current run loop.
// If an existing SCNetworkReachabilityRef was found in the cache, we can reuse it and register
// to receive notifications from it in the current run loop, which may be different than the run loop
// that was previously used when registering the SCNetworkReachabilityRef for notifications.
// -scheduleOnRunLoop: will schedule only if network status notifications are enabled in the Reachability instance.
// By default, they are not enabled.
[query scheduleOnRunLoop:[NSRunLoop currentRunLoop]];
// ... and add it to the cache.
[self.reachabilityQueries setObject:query forKey:addressString];
return reachabilityRefForA
- (NetworkStatus)remoteHostStatus
If the current host name or address is reachable, determine which network interface it is reachable through.
If the host is reachable and the reachability flags include kSCNetworkReachabilityFlagsIsWWAN, it
is reachable through the carrier data network. If the host is reachable and the reachability
flags do not include kSCNetworkReachabilityFlagsIsWWAN, it is reachable through the WiFi network.
SCNetworkReachabilityRef reachabilityRef =
if (self.hostName) {
reachabilityRef = [self reachabilityRefForHostName:self.hostName];
} else if (self.address) {
reachabilityRef = [self reachabilityRefForAddress:self.address];
NSAssert(self.hostName != nil && self.address != nil, @"No hostName or address specified. Cannot determine reachability.");
return NotR
if (!reachabilityRef) {
return NotR
SCNetworkReachabilityFlags reachabilityF
BOOL gotFlags = SCNetworkReachabilityGetFlags(reachabilityRef, &reachabilityFlags);
if (!gotFlags) {
return NotR
BOOL reachable = [self isReachableWithoutRequiringConnection:reachabilityFlags];
if (!reachable) {
return NotR
if (reachabilityFlags & ReachableViaCarrierDataNetwork) {
return ReachableViaCarrierDataN
return ReachableViaWiFiN
- (NetworkStatus)internetConnectionStatus
To determine if the device has an Internet connection, query the address
0.0.0.0. If it's reachable without requiring a connection, first check
for the kSCNetworkReachabilityFlagsIsDirect flag, which tell us if the connection
is to an ad-hoc WiFi network. If it is not, the device can access the Internet.
The next thing to determine is how the device can access the Internet, which
can either be through the carrier data network (EDGE or other service) or through
a WiFi connection.
Note: Knowing that the device has an Internet connection is not the same as
knowing if the device can reach a particular host. To know that, use
-[Reachability remoteHostStatus].
SCNetworkReachabilityFlags defaultRouteF
BOOL defaultRouteIsAvailable = [self isNetworkAvailableFlags:&defaultRouteFlags];
if (defaultRouteIsAvailable) {
if (defaultRouteFlags & kSCNetworkReachabilityFlagsIsDirect) {
// The connection is to an ad-hoc WiFi network, so Internet access is not available.
return NotR
else if (defaultRouteFlags & ReachableViaCarrierDataNetwork) {
return ReachableViaCarrierDataN
return ReachableViaWiFiN
return NotR
- (NetworkStatus)localWiFiConnectionStatus
SCNetworkReachabilityFlags selfAssignedAddressF
To determine if the WiFi connection is to a local ad-hoc network,
check the availability of the address 169.254.x.x. That's an address
in the self-assigned range, and the device will have a self-assigned IP
when it's connected to a ad-hoc WiFi network. So to test if the device
has a self-assigned IP, look for the kSCNetworkReachabilityFlagsIsDirect flag
in the address query. If it's present, we know that the WiFi connection
is to an ad-hoc network.
// This returns YES if the address 169.254.0.0 is reachable without requiring a connection.
BOOL hasLinkLocalNetworkAccess = [self isAdHocWiFiNetworkAvailableFlags:&selfAssignedAddressFlags];
if (hasLinkLocalNetworkAccess && (selfAssignedAddressFlags & kSCNetworkReachabilityFlagsIsDirect)) {
return ReachableViaWiFiN
return NotR
// Convert an IP address from an NSString to a sockaddr_in * that can be used to create
// the reachability request.
- (BOOL)addressFromString:(NSString *)IPAddress address:(struct sockaddr_in *)address
if (!IPAddress || ![IPAddress length]) {
return NO;
memset((char *) address, sizeof(struct sockaddr_in), 0);
address-&sin_family = AF_INET;
address-&sin_len = sizeof(struct sockaddr_in);
int conversionResult = inet_aton([IPAddress UTF8String], &address-&sin_addr);
if (conversionResult == 0) {
NSAssert1(conversionResult != 1, @"Failed to convert the IP address string into a sockaddr_in: %@", IPAddress);
return NO;
return YES;
@interface ReachabilityQuery ()
- (CFRunLoopRef)startListeningForReachabilityChanges:(SCNetworkReachabilityRef)reachability onRunLoop:(CFRunLoopRef)runL
@implementation ReachabilityQuery
@synthesize reachabilityRef = _reachabilityR
@synthesize runLoops = _runL
@synthesize hostNameOrAddress = _hostNameOrA
- (id)init
self = [super init];
if (self != nil) {
self.runLoops = CFArrayCreateMutable(kCFAllocatorDefault, 0, NULL);
- (void)dealloc
CFRelease(self.runLoops);
[super dealloc];
- (BOOL)isScheduledOnRunLoop:(CFRunLoopRef)runLoop
NSUInteger runLoopCounter, maxRunLoops = CFArrayGetCount(self.runLoops);
for (runLoopCounter = 0; runLoopCounter & maxRunL runLoopCounter++) {
CFRunLoopRef nextRunLoop = (CFRunLoopRef)CFArrayGetValueAtIndex(self.runLoops, runLoopCounter);
if (nextRunLoop == runLoop) {
return YES;
return NO;
- (void)scheduleOnRunLoop:(NSRunLoop *)inRunLoop
// Only register for network state changes if the client has specifically enabled them.
if ([[Reachability sharedReachability] networkStatusNotificationsEnabled] == NO) {
if (!inRunLoop) {
CFRunLoopRef runLoop = [inRunLoop getCFRunLoop];
// Notifications of status changes for each reachability query can be scheduled on multiple run loops.
// To support that, register for notifications for each runLoop.
// -isScheduledOnRunLoop: iterates over all of the run loops that have previously been used
// to register for notifications. If one is found that matches the passed in runLoop argument, there's
// no need to register for notifications again. If one is not found, register for notifications
// using the current runLoop.
if (![self isScheduledOnRunLoop:runLoop]) {
CFRunLoopRef notificationRunLoop = [self startListeningForReachabilityChanges:self.reachabilityRef onRunLoop:runLoop];
if (notificationRunLoop) {
CFArrayAppendValue(self.runLoops, notificationRunLoop);
// Register to receive changes to the 'reachability' query so that we can update the
// user interface when the network state changes.
- (CFRunLoopRef)startListeningForReachabilityChanges:(SCNetworkReachabilityRef)reachability onRunLoop:(CFRunLoopRef)runLoop
if (!reachability) {
return NULL;
if (!runLoop) {
return NULL;
SCNetworkReachabilityContext
context = {0, self, NULL, NULL, NULL};
SCNetworkReachabilitySetCallback(reachability, ReachabilityCallback, &context);
SCNetworkReachabilityScheduleWithRunLoop(reachability, runLoop, kCFRunLoopDefaultMode);
return runL
本文地址: &
我正在使用iPhone应用程式,我想要检查手机是否可以拨打电话(如果没有,则提醒使用者)。这可能是因为没有可用的移动服务,或者如果用户将电话置于“飞行模式”。
我看过苹果的文档,找到任何东西,让我检查这一点。我缺少某些东西,或者苹果不会将这些信息暴露给应用程序?
编辑:为了强调,我不想检查IP网络连接,
解决方案 查看 reachability.m
。虽然我对单元信号强度不是肯定的,但如果存在类似的东西,它将包含在这个文件中。
这里是一个如何使用它来检测网络可达性:
Reachability.m:
=====重要=====
这是演示API的示例代码,技术或技术在发展。 虽然此示例代码已经过技术准确性审核,但不是 final。 Apple正在提供此信息,以帮助您计划采用本文所述的技术和编程接口。此信息可能会更改,并且基于此示例代码实现的软件应该使用最终操作系统软件和最终文档进行测试。此示例代码的较新的版本可以提供API的未来种子或技术。有关此和其他开发人员文档的更新的信息,请查看New&在后续文档中更新侧边栏种子。
===================
文件:Reachability.m 摘要:SystemConfiguration框架包装器。
免责声明:重要提示:此Apple软件由Apple Inc.提供给您。(“Apple”)考虑您同意以下条款,并且您的使用,安装,修改或重新分发此Apple软件构成接受这些条款。如果您不同意这些条款,请不要使用,安装,修改或重新分发这个苹果软件。
考虑到您同意遵守以下条款,并且符合这些条款,Apple将授予您个人非独家许可,根据 Apple在这方面的版权原始苹果软件(“苹果软件”)到以源代码和/或二进制形式使用,复制,修改和重新分发Apple软件,带有或不带修改;如果您重新分发 Apple Software的全部内容并且无需修改,您必须保留本通知以及Apple Software的所有此类重新分发中的以下文本和免责声明。
Apple Inc.的名称,商标,服务标志或徽标不得在未经Apple的书面许可的情况下使用来支持或促销来自Apple软件的产品。除非本通知中明确规定,没有其他权利或许可,明示或暗示,由苹果授予,包括但不限于您的可能侵犯的任何专利权衍生作品或其他作品,苹果软件可能是。
Apple软件由Apple以“原样”提供。苹果产生保证,明示或暗示,包括但不限于暗示非侵权,适销性和特定适用性的保证目的,关于苹果软件或其使用和操作或IN 与您的产品组合。
在任何情况下,苹果均不对任何特殊,间接,偶发或任何其他损失负责(包括但不限于购买替代品bb b商品或服务的损失使用,数据或利润;或业务中断)出现使用,复制,修改和/或出现的苹果软件,无论出现的原因以及根据理论的合同,侵权(包括疏忽),严格责任或其他,即使苹果已被告知这种损害的可能性。
版权所有(C)2008 Apple Inc.保留所有权利。
#import& sys / socket.h&
#import& netinet / in.h&
#import& netinet6 / in6.h&
#import& arpa / inet.h&
#import& ifaddrs.h&
#include& netdb.h&
#import“Reachability.h” #import& SystemConfiguration / SCNetworkReachability.h&
static NSString * kLinkLocalAddressKey = @“169.254.0.0”;
static NSString * kDefaultRouteKey = @“0.0.0.0”;
static可达性* _sharedR
//一个类扩展,声明这个类的内部方法。
@interface Reachability()
- (BOOL)isAdHocWiFiNetworkAvailableFlags:(SCNetworkReachabilityFlags *)outF
- (BOOL)isNetworkAvailableFlags:(SCNetworkReachabilityFlags *)outF
- (BOOL)isReachableWithoutRequiringConnection:(SCNetworkReachabilityFlags)
- (SCNetworkReachabilityRef)reachabilityRefForHostName:(NSString *)hostN
- (SCNetworkReachabilityRef)reachabilityRefForAddress:(NSString *)
- (BOOL)addressFromString:(NSString *)IPAddress address:(struct sockaddr_in *)outA
- (void)stopListeningForReachabilityC
@implementation可达性
@synthesize networkStatusNotificationsEnabled = _networkStatusNotificationsE
@synthesize hostName = _hostN
@synthesize address = _
@synthesize reachabilityQueries = _reachabilityQ
+(Reachability *)sharedReachability
{ if(!_sharedReachability){ _sharedReachability = [[Reachability alloc] init];
//可访问性客户端通常在调用其中一个状态方法之前调用[[Reachability sharedReachability] setHostName:]
_sharedReachability.hostName =
_sharedReachability.address =
_sharedReachability.networkStatusNotificationsEnabled = NO;
_sharedReachability.reachabilityQueries = [[NSMutableDictionary alloc] init]; }
return _sharedR }
- (void)dealloc
{ [self stopListeningForReachabilityChanges];
[_sharedReachability.reachabilityQueries release];
[_sharedReachability release];
[super dealloc] }
- (BOOL)isReachableWithoutRequiringConnection:(SCNetworkReachabilityFlags)flags
{ // kSCNetworkReachabilityFlagsReachable表示指定的节点名或地址可以 //达到使用当前网络配置。
BOOL isReachable = flags& kSCNetworkReachabilityFlagsR
//此标志表示指定的节点名或地址可以使用当前网络配置到达 //,但必须首先建立 //连接。
//例如,对于当前不活动的拨号 //连接,将返回此状态,但可以处理 //网络流量目标系统。
//如果标志为false,我们没有连接。但是因为CFNetwork
//自动尝试启动WWAN连接,如果存在WWAN可达性 //标志,则不需要连接。
BOOL noConnectionRequired =!(flags& kSCNetworkReachabilityFlagsConnectionRequired);
if((flags& kSCNetworkReachabilityFlagsIsWWAN)){ noConnectionRequired = YES; }
return(isReachable&& noConnectionRequired)? YES:NO; }
//返回当前网络配置是否可以访问当前主机名。
- (BOOL)isHostReachable:(NSString *)host
{ if(!host ||![host length]){ return NO; }
SCNetworkReachabilityFlags标志;
SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithName(NULL,[host UTF8String]);
BOOL gotFlags = SCNetworkReachabilityGetFlags(reachability,& flags);
CFRelease(reachability);
if(!gotFlags){ return NO; }
return [self isReachableWithoutRequiringConnection:flags]; }
//如果地址169.254.0.0可达而不需要连接,则返回YES。
- (BOOL)isAdHocWiFiNetworkAvailableFlags:(SCNetworkReachabilityFlags *)outFlags
{ //查看与此查询匹配的可达性查询的缓存。
ReachabilityQuery * query = [self.reachabilityQueries objectForKey:kLinkLocalAddressKey];
SCNetworkReachabilityRef adHocWiFiNetworkReachability = query.reachabilityR
//如果没有找到缓存的可达性查询,请创建一个。
if(!adHocWiFiNetworkReachability){
//构建sockaddr_in,我们可以传递到地址可达性查询。
struct sockaddr_
bzero(& sin,sizeof(sin));
sin.sin_len = sizeof(sin);
sin.sin_family = AF_INET;
// IN_LINKLOCALNETNUM定义在& netinet / in.h& as 169.254.0.0
sin.sin_addr.s_addr = htonl(IN_LINKLOCALNETNUM);
adHocWiFiNetworkReachability = SCNetworkReachabilityCreateWithAddress(NULL,(struct sockaddr *)& sin);
query = [[[ReachabilityQuery alloc] init] autorelease];
query.hostNameOrAddress = kLinkLocalAddressK
query.reachabilityRef = adHocWiFiNetworkR
//将可达性查询添加到缓存。
[self.reachabilityQueries setObject:query forKey:kLinkLocalAddressKey]; }
//如果需要,在当前运行循环中注册SCNetworkReachabilityRef的通知。
//如果在缓存中找到一个现有的SCNetworkReachabilityRef,我们可以重用它并注册 //在当前运行循环中接收来自它的通知,这可能不同于运行循环 //以前在为通知注册SCNetworkReachabilityRef时使用。
// -scheduleOnRunLoop:仅当在Reachability实例中启用网络状态通知时才会进行计划。
//默认情况下,它们未启用。
[query scheduleOnRunLoop:[NSRunLoop currentRunLoop]];
SCNetworkReachabilityFlags addressReachabilityF
BOOL gotFlags = SCNetworkReachabilityGetFlags(adHocWiFiNetworkReachability,& addressReachabilityFlags);
if(!gotFlags){ //获取可达性标志时出错。
return NO; }
//这个方法的调用者可能想使用可达性标志,所以如果一个'out'参数 //被传入, 。
if(outFlags){ * outFlags = addressReachabilityF }
return [self isReachableWithoutRequiringConnection:addressReachabilityFlags]; }
// ReachabilityCallback被注册为startListeningForReachabilityChanges中网络状态更改的回调。
static void ReachabilityCallback(SCNetworkReachabilityRef target,SCNetworkReachabilityFlags flags,void * info) { NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
//发布通知以通知客户端网络可达性已更改。
[[NSNotificationCenter defaultCenter] postNotificationName:@“kNetworkReachabilityChangedNotification”object:nil];
[pool release]; }
//对地址0.0.0.0执行可达性查询。如果在没有 //需要连接的情况下可访问该地址,则可以使用网络接口。我们必须做更多的工作到 //确定哪个网络接口可用。
- (BOOL)isNetworkAvailableFlags:(SCNetworkReachabilityFlags *)outFlags
{ ReachabilityQuery * query = [self.reachabilityQueries objectForKey:kDefaultRouteKey];
SCNetworkReachabilityRef defaultRouteReachability = query.reachabilityR
if(!defaultRouteReachability){
struct sockaddr_in zeroA
bzero(& zeroAddress,sizeof(zeroAddress));
zeroAddress.sin_len = sizeof(zeroAddress);
zeroAddress.sin_family = AF_INET;
defaultRouteReachability = SCNetworkReachabilityCreateWithAddress(NULL,(struct sockaddr *)& zeroAddress);
ReachabilityQuery * query = [[[ReachabilityQuery alloc] init] autorelease];
query.hostNameOrAddress = kDefaultRouteK
query.reachabilityRef = defaultRouteR
[self.reachabilityQueries setObject:query forKey:kDefaultRouteKey]; }
//如果需要,在当前运行循环中注册SCNetworkReachabilityRef的通知。
//如果在缓存中找到一个现有的SCNetworkReachabilityRef,我们可以重用它并注册 //在当前运行循环中接收来自它的通知,这可能不同于运行循环 //以前在为通知注册SCNetworkReachabilityRef时使用。
// -scheduleOnRunLoop:仅当在Reachability实例中启用网络状态通知时才会进行计划。
//默认情况下,它们未启用。
[query scheduleOnRunLoop:[NSRunLoop currentRunLoop]];
SCNetworkReachabilityFlags标志;
BOOL gotFlags = SCNetworkReachabilityGetFlags(defaultRouteReachability,& flags);
if(!gotFlags){ return NO; }
BOOL isReachable = [self isReachableWithoutRequiringConnection:flags];
//这个方法的调用者可能想使用可达性标志,因此如果一个'out'参数 //被传入,则为它分配可达性标志。
if(outFlags){ * outFlags = }
return isR }
//当应用程序终止时成为一个好的公民注销网络状态更改。
- (void)stopListeningForReachabilityChanges
{ //遍历保存SCNetworkReachabilityRefs的缓存以实现可达性 //查询特定主机或地址。
NSEnumerator * enumerator = [self.reachabilityQueries objectEnumerator];
ReachabilityQuery * reachabilityQ
while(reachabilityQuery = [enumerator nextObject]){
CFArrayRef runLoops = reachabilityQuery.runL
NSUInteger runLoopCounter,maxRunLoops = CFArrayGetCount(runLoops);
for(runLoopCounter = 0; runLoopCounter <maxRunL runLoopCounter ++){ CFRunLoopRef nextRunLoop =(CFRunLoopRef)CFArrayGetValueAtIndex(runLoops,runLoopCounter);
SCNetworkReachabilityUnscheduleFromRunLoop(reachabilityQuery.reachabilityRef,nextRunLoop,kCFRunLoopDefaultMode); }
CFArrayRemoveAllValues(reachabilityQuery.runLoops); } }
/ * 为hostName创建一个SCNetworkReachabilityRef,它允许我们确定hostName 当前是否可达,并让我们注册接收hostName的可达性发生变化时的通知。
- (SCNetworkReachabilityRef)reachabilityRefForHostName:(NSString *)hostName
{ if(!hostName ||![hostName length]){ return NULL; }
//在缓存中查找hostName的现有SCNetworkReachabilityRef。
ReachabilityQuery * cachedQuery = [self.reachabilityQueries objectForKey:hostName];
SCNetworkReachabilityRef reachabilityRefForHostName = cachedQuery.reachabilityR
if(reachabilityRefForHostName){ return reachabilityRefForHostN }
//找不到hostName的现有SCNetworkReachabilityRef,所以创建一个...
reachabilityRefForHostName = SCNetworkReachabilityCreateWithName(kCFAllocatorDefault,[hostName UTF8String]);
NSAssert1(reachabilityRefForHostName!= NULL,@“无法为主机:%@”,hostName创建SCNetworkReachabilityRef);
ReachabilityQuery * query = [[[ReachabilityQuery alloc] init] autorelease];
query.hostNameOrAddress = hostN
query.reachabilityRef = reachabilityRefForHostN
//如果需要,在当前运行循环中注册SCNetworkReachabilityRef的通知。
//如果在缓存中找到一个现有的SCNetworkReachabilityRef,我们可以重用它并注册 //在当前运行循环中接收来自它的通知,这可能不同于运行循环 //以前在为通知注册SCNetworkReachabilityRef时使用。
// -scheduleOnRunLoop:仅当在Reachability实例中启用网络状态通知时才会进行计划。
//默认情况下,它们未启用。
[query scheduleOnRunLoop:[NSRunLoop currentRunLoop]];
// ...并将其添加到缓存。
[self.reachabilityQueries setObject:query forKey:hostName];
return reachabilityRefForHostN }
/ * 为addressString中的IP地址创建一个SCNetworkReachabilityRef,这使我们可以确定的地址是否可达,并让我们注册接收当的可达性地址改变时通知。
- (SCNetworkReachabilityRef)reachabilityRefForAddress:(NSString *)addressString
{ if(!addressString ||![addressString length]){ return NULL; }
struct sockaddr_
BOOL gotAddress = [self addressFromString:addressString address:& address];
//尝试将addressString转换为sockaddr_in失败。
if(!gotAddress){ NSAssert1(gotAddress!= NO,@“无法将IP地址字符串转换为sockaddr_in:%@”,addressString);
return NULL; }
//在缓存中查找现有的SCNetworkReachabilityRef的addressString。
ReachabilityQuery * cachedQuery = [self.reachabilityQueries objectForKey:addressString];
SCNetworkReachabilityRef reachabilityRefForAddress = cachedQuery.reachabilityR
if(reachabilityRefForAddress){ return reachabilityRefForA }
//找不到用于addressString的现有SCNetworkReachabilityRef,所以创建一个...
reachabilityRefForAddress = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault,(struct sockaddr *)& address) ;
NSAssert1(reachabilityRefForAddress!= NULL,@“无法为地址:%@”创建SCNetworkReachabilityRef,addressString);
ReachabilityQuery * query = [[[ReachabilityQuery alloc] init] autorelease];
query.hostNameOrAddress = addressS
query.reachabilityRef = reachabilityRefForA
//如果需要,在当前运行循环中注册SCNetworkReachabilityRef的通知。
//如果在缓存中找到一个现有的SCNetworkReachabilityRef,我们可以重用它并注册 //在当前运行循环中接收来自它的通知,这可能不同于运行循环 //以前在为通知注册SCNetworkReachabilityRef时使用。
// -scheduleOnRunLoop:仅当在Reachability实例中启用网络状态通知时才会进行计划。
//默认情况下,它们未启用。
[query scheduleOnRunLoop:[NSRunLoop currentRunLoop]];
// ...并将其添加到缓存。
[self.reachabilityQueries setObject:query forKey:addressString];
return reachabilityRefForA }
- (NetworkStatus)remoteHostStatus
{ / * 如果当前主机名或地址可访问,请确定可访问哪个网络接口通过。 如果主机可访问,并且可达性标志包括kSCNetworkReachabilityFlagsIsWWAN,则它可以通过运营商数据网络到达。如果主机可达且可达性标志不包括kSCNetworkReachabilityFlagsIsWWAN,则可通过WiFi网络到达。
SCNetworkReachabilityRef reachabilityRef =
if(self.hostName){ reachabilityRef = [self reachabilityRefForHostName:self.hostName];
} else if(self.address){ reachabilityRef = [self reachabilityRefForAddress:self.address];
} else { NSAssert(self.hostName!= nil&& self.address!= nil,@“没有指定hostName或地址,无法确定可达性。
return NotR }
if(!reachabilityRef){ return NotR }
SCNetworkReachabilityFlags reachabilityF
BOOL getsFlags = SCNetworkReachabilityGetFlags(reachabilityRef,& reachabilityFlags);
if(!gotFlags){ return NotR }
BOOL reachable = [self isReachableWithoutRequiringConnection:reachabilityFlags];
if(!reachable){ return NotR }
if(reachabilityFlags& ReachableViaCarrierDataNetwork){ return ReachableViaCarrierDataN }
return ReachableViaWiFiN }
- (NetworkStatus)internetConnectionStatus
{ / * 要确定设备是否具有Internet连接,请查询地址 0.0.0.0。如果它不需要连接就可以访问,首先检查的kSCNetworkReachabilityFlagsIsDirect标志,它告诉我们连接是否是一个ad-hoc WiFi网络。如果不是,则设备可以访问因特网。 接下来要确定的是设备如何访问互联网,可以通过运营商数据网络(EDGE或其他服务)或通过 WiFi连接。
注意:知道设备具有Internet连接与不同,知道设备是否可以访问特定主机。要知道,使用
[Reachability remoteHostStatus]。
SCNetworkReachabilityFlags defaultRouteF
BOOL defaultRouteIsAvailable = [self isNetworkAvailableFlags:& defaultRouteFlags];
if(defaultRouteIsAvailable){
if(defaultRouteFlags& kSCNetworkReachabilityFlagsIsDirect){
//连接到ad-hoc WiFi网络,不可用。
return NotR }
else if(defaultRouteFlags& ReachableViaCarrierDataNetwork){ return ReachableViaCarrierDataN }
return ReachableViaWiFiN }
return NotR }
- (NetworkStatus)localWiFiConnectionStatus
{ SCNetworkReachabilityFlags selfAssignedAddressF
/ * 要确定WiFi连接是否是本地ad-hoc网络,检查地址169.254.x.x的可用性。这是在自我分配范围内的地址,并且当设备连接到ad-hoc WiFi网络时,该设备将具有自分配的IP 。因此,要测试设备是否具有自我分配的IP,请在地址查询中查找kSCNetworkReachabilityFlagsIsDirect标志。如果它存在,我们知道WiFi连接是到ad-hoc网络。
//如果地址169.254.0.0可达而不需要连接,则返回YES。
BOOL hasLinkLocalNetworkAccess = [self isAdHocWiFiNetworkAvailableFlags:& selfAssignedAddressFlags];
if(hasLinkLocalNetworkAccess&&(selfAssignedAddressFlags& kSCNetworkReachabilityFlagsIsDirect)){ return ReachableViaWiFiN }
return NotR }
//将IP地址从NSString转换为sockaddr_in *,可用于创建 //可达性请求。
- (BOOL)addressFromString:(NSString *)IPAddress address:(struct sockaddr_in *)address
{ if(!IPAddress ||![IPAddress length]){ return没有; }
memset((char *)address,sizeof(struct sockaddr_in),0);
address-& sin_family = AF_INET;
address-& sin_len = sizeof(struct sockaddr_in);
int conversionResult = inet_aton([IPAddress UTF8String],& address-& sin_addr);
if(conversionResult == 0){ NSAssert1(conversionResult!= 1,@“无法将IP地址字符串转换为sockaddr_in:%@”,IPAddress);
return NO; }
return YES; }
@interface ReachabilityQuery()
- (CFRunLoopRef)startListeningForReachabilityChanges:(SCNetworkReachabilityRef)reachability onRunLoop:(CFRunLoopRef)runL
@implementation ReachabilityQuery
@synthesize reachabilityRef = _reachabilityR
@synthesize runLoops = _runL
@synthesize hostNameOrAddress = _hostNameOrA
- (id)init
{ self = [super init];
if(self!= nil){ self.runLoops = CFArrayCreateMutable(kCFAllocatorDefault,0,NULL); }
- (void)dealloc
{ CFRelease(self.runLoops);
[super dealloc] }
- (BOOL)isScheduledOnRunLoop:(CFRunLoopRef)runLoop
{ NSUInteger runLoopCounter,maxRunLoops = CFArrayGetCount(self.runLoops);
for(runLoopCounter = 0; runLoopCounter <maxRunL runLoopCounter ++){ CFRunLoopRef nextRunLoop =(CFRunLoopRef)CFArrayGetValueAtIndex(self.runLoops,runLoopCounter);
if(nextRunLoop == runLoop){ return YES; } }
return NO; }
- (void)scheduleOnRunLoop:(NSRunLoop *)inRunLoop
{ //仅当客户端特别启用它们时才注册网络状态更改。
if([[Reachability sharedReachability] networkStatusNotificationsEnabled] == NO){ }
if(!inRunLoop){ }
CFRunLoopRef runLoop = [inRunLoop getCFRunLoop];
//每个可达性查询的状态更改通知可以在多个运行循环上计划。
//为了支持,注册每个runLoop的通知。
// -isScheduledOnRunLoop:遍历所有以前使用的运行循环 //注册通知。如果发现一个匹配传递的runLoop参数,则有 //不需要再次注册通知。如果没有找到,则使用当前runLoop注册通知 //。
if(![self isScheduledOnRunLoop:runLoop]){
CFRunLoopRef notificationRunLoop = [self startListeningForReachabilityChanges:self.reachabilityRef onRunLoop:runLoop];
if(notificationRunLoop){ CFArrayAppendValue(self.runLoops,notificationRunLoop); } } }
//注册以接收对“可达性”查询的更改,以便我们可以更新 //用户界面网络状态改变。
- (CFRunLoopRef)startListeningForReachabilityChanges:(SCNetworkReachabilityRef)reachability onRunLoop:(CFRunLoopRef)runLoop
{ if(!reachability){ return NULL; }
if(!runLoop){ return NULL; }
SCNetworkReachabilityContext context = {0,self,NULL,NULL,NULL};
SCNetworkReachabilitySetCallback(reachability,ReachabilityCallback,& context);
SCNetworkReachabilityScheduleWithRunLoop(reachability,runLoop,kCFRunLoopDefaultMode);
return runL }
本文地址: &
扫一扫关注官方微信

我要回帖

更多关于 无线网数据包收到0 的文章

 

随机推荐