I want get a call when network is change of iPhone.
I Use Reachability.m of Apple guide like this:
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
}
I test change mobile(4G) to wifi1
recives call like
Status4G
StatusNone
StatusWifi1
When change form wifi1 to wifi2
StatusWifi1
StatusNone
StatusWifi2
However, sometimes, when wifi changes very fast and did not change to StatusNone
, I did not get callback when i change wifi1 to wifi2 or the other way round.
What i want get is
StatusWifi1
StatusWifi2
-------------------------UPDATE----------------------------
Thanks @Hitesh Surani, now my question is sometimes on some devices, i did not received disconnect state
, I try to use
[self reachabilityWithAddress: @"www.google.com"]
Replace
[self reachabilityWithAddress: (const struct sockaddr *) &zeroAddress]
Now, I can received call back when wifi is change even it did not into disconnect state
, but i still didn't known why, here is the state change:
//wifi1:
1 kSCNetworkReachabilityFlagsReachable
//wifi1 -> wifi2
2 kSCNetworkReachabilityFlagsReachable | kSCNetworkReachabilityFlagsTransientConnection
3 kSCNetworkReachabilityFlagsReachable
when change wifi, there is tmp state kSCNetworkReachabilityFlagsReachable | kSCNetworkReachabilityFlagsTransientConnection
, that's why i can detect wifi changes, but what does kSCNetworkReachabilityFlagsTransientConnection
mean? i read the doc of Apple, still be confused.
Thank you for asking great qestion.
Mainly Reachability
class is use for tracking of internet connectivity changes. There is no provsion for detect wifi changed notification. So in one word Reachability
class not provide this type of funtionality. If you want to achieved your requirement then below customisation required.
You can achived wifi changed notification as below.
When your wifi connection changed or switch to any other network then you have received disconnect state for fraction of second. So reachabilityChanged
method is called.
By using below code, You can get wifi information such as BSSID,SSID(Name) and SSID data. Just store wifi info into local.
Put below code into reachabilityChanged
method.
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 provide com.apple.system.config.network_change
to listen wifi changes notification. Basically it is part of Core Foundation
framework. I am sure it will work for you.
Please add below code to listen wifi changes.
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. Find reference from Here.