【问题标题】:How to check for local Wi-Fi (not just cellular connection) using iPhone SDK?如何使用 iPhone SDK 检查本地 Wi-Fi(不仅仅是蜂窝连接)?
【发布时间】:2024-05-02 23:40:02
【问题描述】:

我目前正在使用以下方法检查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”(显然还有 Matt Brown)。

【问题讨论】:

  • 不幸的是,这不起作用,至少不能确定 Wi-Fi 是否被激活。您可以打开 Wi-Fi,如果 Wi-Fi 适配器未连接到网络,此例程仍将返回 false。不过,谢谢。

标签: iphone objective-c cocoa-touch


【解决方案1】:

首先,修改你的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连接则会声明无连接。

【讨论】:

    【解决方案2】:

    查看此链接: http://developer.apple.com/iphone/library/samplecode/Reachability/

    您必须是注册开发者才能下载代码示例。而且,这很重要! Reachability API 适用于 3.0+ SDK,它会在较低版本中崩溃。

    顺便说一句,通过新的 HIG,所有依赖 WiFi 连接的应用程序都必须在其缺失时提醒用户,即如果设备未连接到 Wifi,请告知用户。

    【讨论】:

      【解决方案3】:

      斯威夫特版本

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

      【讨论】:

        【解决方案4】:

        查看 Apple 提供的 Reachability 类。这使您可以检查设备当前具有哪些连接,在 Wifi、蜂窝或无之间。您甚至可以在连接发生变化时注册通知。

        不幸的是,谷歌目前对我不利,但谷歌搜索“iPhone 可达性”将为您提供所需的信息。

        【讨论】:

          【解决方案5】:
          -(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;
          
          }
          

          【讨论】: