I want to detect when the network changes from ethernet to wifi (or wifi to ethernet). I want to have an observer to notify me about this change.
reachability isn't good enough - it's always returns ReachableViaWiFi for both cases.
P.S - There were some questions regarding this topic before, but none of them has a good answer, and since those questions are more than a year old, maybe someone already find out how to do it
In Windows 10, click Start > Settings > Control Panel > Network and Internet > Network and Sharing Center > Change adapter settings. In the list of network connections that opens, select the connection you are using to connect to your ISP (wireless or LAN).
Click the Start button, then click "Control Panel" and type "network status" in the search field at the top right of the window. Click "Network and Sharing" to see a readout of your current network status.
Check the Ethernet cable and connection. Make sure the Ethernet cable is securely plugged into the Ethernet port on both your router and Windows 10 PC. On your router, make sure the Ethernet cable is plugged into the correct Ethernet port—not the Internet port that's used to connect your modem and router.
Please note that a Mac can have multiple active interfaces at the same time and some of these may be Ethernet and some of them may be WiFi. Even if you just monitor the primary interfaces, take note that a Mac can have multiple primary interfaces, one per protocol (e.g. the primary interface for IPv4 may not be the primary one for IPv6).
For demonstration purposes, I will assume that you want to monitor the primary IPv4 interface. Here is code that you can just copy & paste to a swift file and directly run from command line (e.g. swift someFile.swift
):
import Foundation
import SystemConfiguration
let DynamicStore = SCDynamicStoreCreate(
nil, "Name of your App" as CFString,
{ ( _, _, _ ) in PrimaryIPv4InterfaceChanged() }, nil)!
func PrimaryIPv4InterfaceChanged ( ) {
guard let ipv4State = SCDynamicStoreCopyValue(DynamicStore,
"State:/Network/Global/IPv4" as CFString) as? [CFString: Any]
else {
print("No primary IPv4 interface available")
return
}
guard let primaryServiceID =
ipv4State[kSCDynamicStorePropNetPrimaryService]
else { return }
let interfaceStateName =
"Setup:/Network/Service/\(primaryServiceID)/Interface"
as CFString
guard let primaryServiceState = SCDynamicStoreCopyValue(
DynamicStore, interfaceStateName) as? [CFString: Any]
else { return }
guard let hardwareType =
primaryServiceState[kSCPropNetInterfaceHardware]
else { return }
switch hardwareType as! CFString {
case kSCEntNetAirPort:
print("Primary IPv4 interface is now WiFi")
case kSCEntNetEthernet:
print("Primary IPv4 interface is now Ethernet")
default:
print("Primary IPv4 interface is something else")
}
}
SCDynamicStoreSetNotificationKeys(
DynamicStore, [ "State:/Network/Global/IPv4" ] as CFArray, nil)
SCDynamicStoreSetDispatchQueue(DynamicStore, DispatchQueue.main)
dispatchMain()
While it is running, try switching your primary IPv4 interface, pull network cables, turn off WiFi, etc. and watch the output. You can stop it by hitting CTRL+C on your keyboard.
You can access system network preferences through SystemConfiguration
module, which helps you get touch to system preferences store currently resides in the default location /Library/Preferences/SystemConfiguration/preferences.plist
.
Since then, you can receive notifications from SCDynamicStore
by SCDynamicStoreNotifyValue(_:_:)
or retrieve value by SCDynamicStoreCopyValue(_:_:)
.
Example for directly lookup current primary network service:
var store = SCDynamicStoreCreate(nil, "Example" as CFString, nil, nil)
var global = SCDynamicStoreCopyValue(store, "State:/Network/Global/IPv4" as CFString)!
var pref = SCPreferencesCreate(nil, "Example" as CFString, nil)
var service = SCNetworkServiceCopy(pref!, global["PrimaryService"] as! CFString)
var interface = SCNetworkServiceGetInterface(service!)
SCNetworkInterfaceGetInterfaceType(interface!) /// Optional("IEEE80211") -> Wi-Fi
Or create dynamic store with callback and set notification keys to receive notifications as every time primary network service changes the notification is going to fire:
var callback: SCDynamicStoreCallBack = { (store, _, _) in
/* Do anything you want */
}
var store = SCDynamicStoreCreate(nil, "Example" as CFString, callback, nil)
SCDynamicStoreSetNotificationKeys(store!, ["State:/Network/Global/IPv4"] as CFArray, nil)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With