我目前正在使用以下内容检查Wi-Fi是否适用于我的应用程序:
#import <SystemConfiguration/SystemConfiguration.h>
static inline BOOL addressReachable(const struct sockaddr_in *hostAddress);
BOOL localWiFiAvailable()
{
struct sockaddr_in localWifiAddress;
bzero(&localWifiAddress, sizeof(localWifiAddress));
localWifiAddress.sin_len = sizeof(localWifiAddress);
localWifiAddress.sin_family = AF_INET;
// IN_LINKLOCALNETNUM is defined in <netinet/in.h> as 169.254.0.0
localWifiAddress.sin_addr.s_addr = htonl(IN_LINKLOCALNETNUM);
return addressReachable(&localWifiAddress);
}
static inline BOOL addressReachable(const struct sockaddr_in *hostAddress)
{
const SCNetworkReachabilityRef target =
SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault,
(const struct sockaddr *)hostAddress);
if (target != NULL)
{
SCNetworkReachabilityFlags flags = 0;
const BOOL reachable = SCNetworkReachabilityGetFlags(target, &flags);
CFRelease(target);
return reachable && (flags & kSCNetworkFlagsReachable);
}
return NO;
}
然而,当iPhone仅连接到蜂窝网络而不是Wi-Fi网络时,这不会返回NO。有谁知道如何解决这个问题?
所以这就是我最终使用的内容:
#import <arpa/inet.h> // For AF_INET, etc.
#import <ifaddrs.h> // For getifaddrs()
#import <net/if.h> // For IFF_LOOPBACK
BOOL localWiFiAvailable()
{
struct ifaddrs *addresses;
struct ifaddrs *cursor;
BOOL wiFiAvailable = NO;
if (getifaddrs(&addresses) != 0) return NO;
cursor = addresses;
while (cursor != NULL) {
if (cursor -> ifa_addr -> sa_family == AF_INET
&& !(cursor -> ifa_flags & IFF_LOOPBACK)) // Ignore the loopback address
{
// Check for WiFi adapter
if (strcmp(cursor -> ifa_name, "en0") == 0) {
wiFiAvailable = YES;
break;
}
}
cursor = cursor -> ifa_next;
}
freeifaddrs(addresses);
return wiFiAvailable;
}
谢谢“unforgiven”(显然是马特·布朗)。
答案 0 :(得分:30)
首先,修改addressReachable方法。而不是
return reachable && (flags & kSCNetworkFlagsReachable);
添加以下内容:
BOOL isReachable = ((flags & kSCNetworkFlagsReachable) != 0);
BOOL needsConnection = ((flags & kSCNetworkFlagsConnectionRequired) != 0);
return (isReachable && !needsConnection) ? YES : NO;
这是检查可用连接的正确方法。现在,如果您想清楚地区分蜂窝和wifi,请修改您的方法以返回int并使用以下
BOOL isReachable = ((flags & kSCNetworkFlagsReachable) != 0);
BOOL needsConnection = ((flags & kSCNetworkFlagsConnectionRequired) != 0);
if(isReachable && !needsConnection) // connection is available
{
// determine what type of connection is available
BOOL isCellularConnection = ((flags & kSCNetworkReachabilityFlagsIsWWAN) != 0);
NSString *wifiIPAddress = [self getWiFiIPAddress];
if(isCellularConnection)
return 1; // cellular connection available
if(wifiIPAddress)
return 2; // wifi connection available
}
else
return 0; // no connection at all
getWiFiIPAddress方法由Matt Brown提供,可以找到here。
还有一件事。 kSCNetworkReachabilityFlagsIsDirect标志可以告诉您网络流量是通过网关还是直接到达。这在某些情况下可能会有所帮助。
代码在设备上正常运行。在模拟器上,当您通过以太网电缆连接时,它将声明您通过wifi连接,并且如果您通过wifi连接将声明没有连接。
答案 1 :(得分:4)
查看此链接: http://developer.apple.com/iphone/library/samplecode/Reachability/
您必须是注册开发人员才能下载代码示例。而且这很重要! Reachability API适用于3.0+ SDK,它会为较低版本崩溃。
BTW,新的HIG所有依赖WiFi连接的应用都必须提醒用户没有,即如果设备没有连接到Wifi,请让用户知道。答案 2 :(得分:2)
Swift版
import Foundation
import SystemConfiguration
public class Reachability {
class func isInternetAvailable() -> Bool {
let IPaddress = "google.com"//WebServicesUtil.sharedInstance.getHostIPAddress()
if let host_name = IPaddress.cStringUsingEncoding(NSASCIIStringEncoding) {
let reachability =
SCNetworkReachabilityCreateWithName(kCFAllocatorDefault, host_name).takeRetainedValue()
var flags: SCNetworkReachabilityFlags = 0
if SCNetworkReachabilityGetFlags(reachability, &flags) == 0 {
return false
}
let isReachable = (flags & UInt32(kSCNetworkFlagsReachable)) != 0
let needsConnection = (flags & UInt32(kSCNetworkFlagsConnectionRequired)) != 0
return (isReachable && !needsConnection)
}
else {
return false
}
}
}
答案 3 :(得分:1)
查看Apple提供的Reachability类。这允许您检查设备当前具有的连接,Wifi,蜂窝或无。您甚至可以在连接发生变化时注册通知。
不幸的是,谷歌此刻对我不利,但谷歌搜索“iPhone可达性”将为您提供所需。
答案 4 :(得分:1)
-(Bool)isDataSourceAvailableNow
{
BOOL isDataSourceAvailable;
bool success = false;
const char *host_name = [@"www.google.com" cStringUsingEncoding:NSASCIIStringEncoding];
SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithName(NULL, host_name);
if (reachability)
{
SCNetworkReachabilityFlags flags;
success = SCNetworkReachabilityGetFlags(reachability, &flags);
isDataSourceAvailable = success && (flags & kSCNetworkFlagsReachable) && !(flags & kSCNetworkFlagsConnectionRequired);
CFRelease(reachability);
} return isDataSourceAvailable;
}