objective-c 如何使用 iPhone SDK 检查本地 Wi-Fi(不仅仅是蜂窝连接)?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1448411/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 22:13:28  来源:igfitidea点击:

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

iphoneobjective-ccocoa-touch

提问by Michael

I'm currently using the following to check whether Wi-Fiis available for my application:

我目前正在使用以下方法检查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;
}

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?

然而,当 iPhone 仅连接到蜂窝网络而不是 Wi-Fi 网络时,这不会像它应该返回的那样返回 NO。有谁知道如何解决这一问题?

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

感谢“不可原谅”(显然还有马特布朗)。

回答by Massimo Cafaro

First, modify your addressReachable method. Instead of

首先,修改您的 addressReachable 方法。代替

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

这是检查可用连接的正确方法。现在,如果您想清楚地区分蜂窝和 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

The getWiFiIPAddress method is courtesy of Matt Brown, and can be found here.

getWiFiIPAddress 方法由 Matt Brown 提供,可在此处找到。

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.

还有一件事。kSCNetworkReachabilityFlagsIsDirect 标志可以告诉您网络流量是通过网关还是直接到达。这在某些情况下可能会有所帮助。

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.

该代码在设备上正常工作。在模拟器上,当你通过以太网线连接时,它会声明你是通过 wifi 连接的,如果你通过 wifi 连接,它会声明没有连接。

回答by Nava Carmon

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

请参阅此链接: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.

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

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.

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

回答by Prabhu.Somasundaram

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

回答by iKenndac

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.

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

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

不幸的是,谷歌目前对我来说是失败的,但是谷歌搜索“iPhone 可达性”会得到你需要的东西。

回答by Kemo

-(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;

}