首页 文章

iOS可达性SCNetworkReachabilitySetCallback在切换窗体wifi到anthor wifi时不回叫

提问于
浏览
1

我希望在网络改变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]

Reachability.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的文档,仍然感到困惑 .

1 回答

  • 0

    谢谢你提出了很好的问题 .

    主要是 Reachability 类用于跟踪互联网连接的变化 . 没有检测到wifi改变通知的证据 . 所以在一个单词 Reachability class中不提供这种类型的功能 . 如果您想达到您的要求,则需要进行以下定制 .

    您可以通过以下方式获得wifi更改通知 .

    • 当您的wifi连接发生变化或切换到任何其他网络时,您已经收到断开连接状态的小数秒 . 所以 reachabilityChanged 方法被调用 .

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

    • 当网络发生变化时,您可以检查新的wifi信息是否与previos匹配 . 如果没有,则用户连接新的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
                        }
                    }
                }
            }
    

    Update:

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

    Register observer on init and remove on deinit.Here查找参考资料 .

相关问题