我想在 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/