iOS Reachability SCNetworkReachabilitySetCallback 当从 wifi 切换到 anthor wifi 时不回调

标签 ios objective-c xcode networking reachability

我想在 iPhone 网络发生变化时接到电话。

我使用 Apple 指南的 Reachability.m,如下所示:

xxx.m

struct sockaddr_in zeroAddress;
bzero(&zeroAddress, sizeof(zeroAddress));
zeroAddress.sin_len = sizeof(zeroAddress);
zeroAddress.sin_family = AF_INET;
Reachability = [self reachabilityWithAddress: (const struct sockaddr *) &zeroAddress]

可达性.m

BOOL returnValue = NO;
SCNetworkReachabilityContext context = {0, (__bridge void *)(self), NULL, NULL, NULL};
if (SCNetworkReachabilitySetCallback(_reachabilityRef, ReachabilityCallback, &context))
{
    if (SCNetworkReachabilityScheduleWithRunLoop(_reachabilityRef, CFRunLoopGetMain(), kCFRunLoopDefaultMode))
    {
        returnValue = YES;
    }
}
return returnValue;

xxx.m

ReachabilityCallback {
    //do something when network change
}

我测试将手机(4G)更改为wifi1

接听电话

Status4G
StatusNone
StatusWifi1

何时将 wifi1 更改为 wifi2

StatusWifi1
StatusNone
StatusWifi2

但是,有时候,当wifi变化非常快并且没有变化到StatusNone时,当我将 wifi1 更改为 wifi2 或反之亦然时,我没有收到回调。

我想要得到的是

StatusWifi1
StatusWifi2

-------------------------UPDATE----------------------------

谢谢@Hitesh Surani,现在我的问题是有时在某些设备上,我没有收到 disconnect state ,我尝试使用

[self reachabilityWithAddress: @"www.google.com"]

替换

[self reachabilityWithAddress: (const struct sockaddr *) &zeroAddress]

现在,当wifi改变时我可以收到回电,即使它没有变成disconnect state ,但我仍然不知道为什么,这是状态变化:

//wifi1:
1 kSCNetworkReachabilityFlagsReachable

//wifi1 -> wifi2
2 kSCNetworkReachabilityFlagsReachable | kSCNetworkReachabilityFlagsTransientConnection
3 kSCNetworkReachabilityFlagsReachable

更改wifi时,有tmp状态kSCNetworkReachabilityFlagsReachable | kSCNetworkReachabilityFlagsTransientConnection ,这就是为什么我可以检测到 wifi 变化,但是 kSCNetworkReachabilityFlagsTransientConnection 又是什么呢?意思是?我看了Apple的文档,还是很困惑。

最佳答案

感谢您提出很好的问题。

主要是 Reachability 类用于跟踪互联网连接变化。没有检测 wifi 更改通知的规定。因此,总之 Reachability 类不提供这种类型的功能。如果您想实现您的要求,则需要进行以下定制。

您可以按如下方式获得 WiFi 更改通知。

  • 当您的 WiFi 连接发生变化或切换到任何其他网络时,您会在几分之一秒内收到断开连接状态。因此调用了 reachabilityChanged 方法。

  • 通过使用下面的代码,您可以获得WiFi信息,例如BSSID,SSID(名称)和SSID数据。只需将 wifi 信息存储到本地即可。

  • 当网络发生变化时,您可以检查新的 WiFi 信息是否与之前的 WiFi 信息匹配。如果没有,则用户使用新的 wifi 连接。

将以下代码放入 reachabilityChanged 方法中。

import SystemConfiguration.CaptiveNetwork

 func printCurrentWifiInfo() {
            if let interface = CNCopySupportedInterfaces() {
                for i in 0..<CFArrayGetCount(interface) {
                    let interfaceName: UnsafeRawPointer = CFArrayGetValueAtIndex(interface, i)
                    let rec = unsafeBitCast(interfaceName, to: AnyObject.self)
                    if let unsafeInterfaceData = CNCopyCurrentNetworkInfo("\(rec)" as CFString), let interfaceData = unsafeInterfaceData as? [String : AnyObject] {
                        // connected wifi
                        print("BSSID: \(String(describing: interfaceData["BSSID"])), SSID: \(String(describing: interfaceData["SSID"])), SSIDDATA: \(String(describing: interfaceData["SSIDDATA"]))")
                    } else {
                        //Wifi is not connected
                    }
                }
            }
        }

更新:

Apple提供com.apple.system.config.network_change来监听wifi变化通知。基本上它是Core Foundation框架的一部分。我相信它会对您有用。

请添加以下代码来监听 wifi 变化。

 let notificationName = "com.apple.system.config.network_change"


    func onNetworkChange(_ name : String) {
        if (name == notificationName) {
            // Do your stuff
            print("Network was changed")
        }
    }

    func registerObserver() {
        let observer = UnsafeRawPointer(Unmanaged.passUnretained(self).toOpaque())
        CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), observer,
                                        { (nc, observer, name, _, _) -> Swift.Void in
                                            if let observer = observer, let name = name {
                                                let instance = Unmanaged<Reachability>.fromOpaque(observer).takeUnretainedValue()
                                                instance.onNetworkChange(name.rawValue as String)
                                            } },
                                        notificationName as CFString, nil, .deliverImmediately)
    }


    func removeObserver() {
        let observer = UnsafeRawPointer(Unmanaged.passUnretained(self).toOpaque())
        CFNotificationCenterRemoveObserver(CFNotificationCenterGetDarwinNotifyCenter(), observer, nil, nil)
    }

在 init 上注册观察者并在 deinit 上删除。Here 查找引用.

关于iOS Reachability SCNetworkReachabilitySetCallback 当从 wifi 切换到 anthor wifi 时不回调,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50322973/

相关文章:

ios - XCode 6 中的新警告

objective-c - NSDictionary 从 API 中分割数据

xcode - 无法使用 Xcode 7.2.1 在 Xcode 服务器上启动 Xcode 服务

iphone - 从 Ivar 创建 id

ios - Xcode 预 ActionScript 不起作用?

ios - Swift - 如何获取具有初始值设定项的数组的索引?

ios - 这个返回参数是什么意思?

ios - 如何使 UITableViewCell 滑动更粘

android - Xamarin 用户指南

objective-c - 无论构建类型如何,宏 __FILE__、__LINE__ 和 __PRETTY_FUNCTION__ 都可以工作吗?