首页 > 解决方案 > 如何在 Swift 中检测 iOS 设备是否使用 wifi 连接?

问题描述

在一个旧的、基于 Objective-C 的项目中,我一直在使用下面的代码来检测 iOS 设备当前是否使用 Wifi(不是蜂窝)连接。

由于 Objective-C 指针,我尝试将此代码转换为 Swift 5 失败。有没有一种干净的方法可以在 Swift 中使用这个解决方案?

或者现在有没有更好的方法来解决这个问题?我找到了使用SwiftNWPathMonitor(). 虽然它们似乎一般工作,但这些解决方案用于监视连接状态并发送更改通知,而一次性检查不受(很好)支持。

事件虽然这些解决方案可用于获取当前连接状态,但这是使用委托回调方法或闭包完成的。因此,不可能在为“同步”工作(没有回调/闭包)而创建的现有代码中使用这些解决方案。

localWiFiAvailable有没有在 Swift中使用的简单方法?

编码:

+ (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 TARGET_IPHONE_SIMULATOR
                wiFiAvailable = true;
                break;
            #else
                if (strcmp(cursor -> ifa_name, "en0") == 0) {
                    wiFiAvailable = YES;
                    break;
                }
            #endif
        }
        cursor = cursor -> ifa_next;
    }
    
    freeifaddrs(addresses);
    return wiFiAvailable;
}   

为什么NWPathMonitor()不能使用的详细信息:

正如@baronfac 在他的评论中指出的那样,NWPathMonitor()也可以传递当前状态,但这只能使用它的.pathUpdateHandler闭包来完成。

我正在使用可以覆盖souldSendData() -> Bool方法的第三方库。不应允许在移动连接上发送数据,而只能在 WiFi 上发送。这些方法需要立即决定返回真或假。因此,等待关闭是不可能的。

所以,我受到这里现有课程的限制。是的,连接可能随时发生变化,但这是一个不同的问题。例如,NWPathMonitor 可用于在连接更改为移动设备时取消传输。

使用上面显示的代码在 Objectiv-C 中解决这个问题是没有问题的。问题很简单,这样的“直接”解决方案是否也可以在 Swift 中实现。虽然在 Swift 项目中使用 Objectiv-C 代码是可能的,但我更愿意只保留项目 Swift。

标签: iosswift

解决方案


正如 Paulw11 所提到的,推荐的方法是使用 NWPathMonitor。UIViewController 类中的常见做法如下:

private var monitor: NWPathMonitor? 

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)

    monitor = NWPathMonitor()
    monitor?.pathUpdateHandler = { [weak self] path in
        if !path.isExpensive { // this means the device is connected via WiFi
            // enter your code here
        }
    }
    let queue = DispatchQueue(label: "Monitor")
    monitor?.start(queue: queue)    // start to monitor the connection
}

override func viewWillDisappear(_ animated: Bool) {
    monitor?.cancel()    // end to monitor the connection 
    super.viewWillDisappear(animated)
}

编辑:

感谢 FLichter 和 Rob Napier 的澄清。也许它有助于使用这种方法:

func shouldSendData() -> Bool {
    let monitor = NWPathMonitor()
    return !monitor.currentPath.isExpense
}

推荐阅读