检测以太网/ wifi网络更改

时间:2017-01-11 12:07:33

标签: swift macos

我想检测网络何时从以太网变为wifi(或从wifi变为以太网)。我希望有一位观察员通知我这一变化。

可达性不够好 - 它总是会在两种情况下都返回ReachableViaWiFi。

P.S - 之前有一些关于这个主题的问题,但没有一个有好的答案,而且由于这些问题已经超过一年了,也许有人已经知道如何做到这一点

3 个答案:

答案 0 :(得分:9)

您可以通过SystemConfiguration模块访问系统网络偏好设置,这有助于您触摸当前位于默认位置/Library/Preferences/SystemConfiguration/preferences.plist的系统偏好设置商店。

从那时起,您可以SCDynamicStore通过SCDynamicStoreNotifyValue(_:_:)接收通知,或按SCDynamicStoreCopyValue(_:_:)检索价值。

直接查找当前主网络服务的示例:

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

或者使用回调创建动态商店并设置通知键,以便每次主要网络服务更改通知时都会收到通知:

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)

答案 1 :(得分:3)

您可以在bash下运行一个launchd脚本来监控您感兴趣的界面,并在更改时启动。

假设您的有线连接是en0,您可以运行:

./netmon en0

将此脚本另存为netmon并使其chmod +x netmon

可执行
#!/bin/bash
interface=$1

# Get current status of interface whose name is passed, e.g. en0
status(){
   ifconfig $1 | awk '/status:/{print $2}'
}

# Monitor interface until killed, echoing changes in status
previous=$(status $interface)
while :; do
   current=$(status $interface)
   if [ $current != $previous ]; then
      echo $interface now $current
      previous=$current
   fi 
   sleep 5
done

答案 2 :(得分:1)

请注意,Mac可以同时具有多个活动接口,其中一些可能是以太网,有些可能是WiFi。即使您仅监视主要接口,也请注意,Mac可以具有多个主要接口,每个协议一个(例如,IPv4的主要接口可能不是IPv6的主要接口)。

出于演示目的,我将假定您要监视主IPv4接口。这是您可以复制并粘贴到快捷文件并直接从命令行运行的代码(例如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()

当它正在运行时,请尝试切换您的主要IPv4接口,拉网线,关闭WiFi等,然后观察输出。您可以通过按键盘上的CTRL + C来停止它。