How to check for local Wi-Fi (not just cellular connection) using iPhone SDK?
Asked Answered
T

5

25

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).

Thereabout answered 19/9, 2009 at 11:55 Comment(1)
Unfortunately, this doesn't work, at least not for determining if Wi-Fi is activated. You can have Wi-Fi on, and this routine will still return false if the Wi-Fi adapter is not connected to a network. Thanks, though.Throw
M
30

First, modify your addressReachable method. Instead of

return reachable && (flags & kSCNetworkFlagsReachable);

add the following:

BOOL isReachable = ((flags & kSCNetworkFlagsReachable) != 0);
BOOL needsConnection = ((flags & kSCNetworkFlagsConnectionRequired) != 0);
return (isReachable && !needsConnection) ? YES : NO;

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

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

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.

Myrwyn answered 26/9, 2009 at 9:45 Comment(0)
L
4

See this link: http://developer.apple.com/iphone/library/samplecode/Reachability/

You have to be registered developer in order to download the code sample. Also and it's important! Reachability API works for 3.0+ SDKs, it crashes for lower versions.

BTW, by new HIG all applications that rely on WiFi connection have to alert user on its absence, i.e if the device is not connected to Wifi, let user know.

Lightship answered 24/9, 2009 at 4:52 Comment(0)
H
2

Swift version

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
        }
    }
}
Heyes answered 24/4, 2015 at 10:31 Comment(0)
P
1

Check out the Reachability class provided by Apple. This allows you to check what connectivity the device currently has, between Wifi, cellular or none. You can even register for notifications when the connectivity changes.

Unfortunately, Google is down for me at the moment, but Googling "iPhone reachability" will get you what you need.

Prohibit answered 21/9, 2009 at 21:39 Comment(0)
C
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;

}
Cube answered 8/10, 2012 at 11:23 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.