I’m currently using the following to check whether Wi-Fi is available for my application:
#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;
}
This, however, does not return NO as it should when the iPhone is connected only to a cellular network but not a Wi-Fi network. Does anyone know how to fix this?
Edit
So this is what I ended up using:
#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;
}
Thanks “unforgiven” (and Matt Brown apparently).
First, modify your addressReachable method. Instead of
add the following:
This is the proper way to check for a connection available. Now, if you want to clearly distinguish between cellular and wifi, modify your method to return an int and use the following
The getWiFiIPAddress method is courtesy of Matt Brown, and can be found here.
One more thing. The kSCNetworkReachabilityFlagsIsDirect flag can tell you whether the network traffic goes through a gateway or arrives directly. This may be helpful in some cases.
The code works correctly on the device. On the simulator, it will declare that you are connected trough wifi when you are connected through the ethernet cable, and will declare no connection if you are connected through wifi.