8

I’m trying to write a basic Swift script to get the name of the Wi-Fi network I’m connected to on macOS. However, even when connected to Wi-Fi, it prints: Not connected to any Wi-Fi network.

import Foundation
import CoreWLAN

// Create a Wi-Fi client instance
if let wifiClient = CWWiFiClient.shared().interface(),
   let ssid = wifiClient.ssid() {
    print("Connected to Wi-Fi: \(ssid)")
} else {
    print("Not connected to any Wi-Fi network.")
}

Additionally, I tried using the following shell commands:

/System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport -s

but returns a deprecation warning:

WARNING: The airport command line tool is deprecated and will be removed in a future release.
For diagnosing Wi-Fi related issues, use the Wireless Diagnostics app or the wdutil command line tool.

and also with networksetup -getairportnetwork en0:

You are not associated with an AirPort network.

Is there a way to fix this issue or an alternative approach to retrieve the current Wi-Fi SSID without needing sudo access?

Specifications: macOS Sequoia 15.0 Apple Silicon M3 Pro

Update

Today I reset my mac to the factory settings and the system installed Sonoma as the default OS. I have tried both the terminal command networksetup and the swift method and they work fine. After updating again to Sequoi the problem appears again so I think the problem is directly related to This new update. Unfortunately, I can't find any info about deprecation or warnings on both the man and the documentation of both methods.

Comment on possible duplicate

You suggested How to get SSID of currently connected Wifi Network in Swift | iOS 14?, but my problem pertains to macOS and NOT iOS. The code you provided is primarily applicable to iOS due to its usage of CoreLocation for location services. Additionally, my issue also involves shell commands, which suggests that it may be related to other factors beyond just programming.

7
  • Check this it may help you. stackoverflow.com/questions/26517017/… Commented Sep 17, 2024 at 17:06
  • 1
    hi @channu, thanks for your help, unfortunately it doesn't print anything.. It's like I'm not connected to wifi Commented Sep 17, 2024 at 17:45
  • Have you enabled the location permission under sandbox and hardened runtime for your app? Commented Sep 17, 2024 at 22:02
  • 1
    hi @Paulw11, thanks for your comment, No I didn't since is just a script and not an app build with Xcode Commented Sep 18, 2024 at 17:42
  • Huh strange, using CWWiFiClient worked fine for me. E.g. running CWWiFiClient.shared().interface()!.ssid()! in the Swift repl returns my network name exactly. Could this be a sandboxing issue? Commented Oct 13, 2024 at 15:43

4 Answers 4

12

A faster version for Sequoia 15.0–15.5 (which also determines the correct WiFi interface enX):

ipconfig getsummary "$(networksetup -listallhardwareports | awk '/Wi-Fi|AirPort/{getline; print $NF}')" | grep '  SSID : ' | awk -F ': ' '{print $2}'

Takes 46 ms vs. 3.8 s on my system.


As of macOS 15.6, the above no longer works & returns "<redacted>". Even programmatic access through CoreWLAN appears to now require a (developer/non-ad-hoc) signed executable with location entitlements, meaning it can't really be run from a script.

There is an even-hackier CLI work-around (taking 42 ms):

en="$(networksetup -listallhardwareports | awk '/Wi-Fi|AirPort/{getline; print $NF}')"; ipconfig getsummary "$en" | grep -Fxq "  Active : FALSE" || networksetup -listpreferredwirelessnetworks "$en" | sed -n '2s/^\t//p'

Note that this won't work properly on some older versions of macOS (macOS 12 tested), because the list does not appear to be sorted in the same manner. Use an older command for getting the SSID.


Also, if GUI scripting is possible in your environment, something like the following AppleScript is an option. It takes 26 ms on my system. Note, though, that GUI scripting is prone to breakage (though perhaps not moreso than what Apple has been doing with all the networking command line tools lately! 😤). It's only tested in macOS 15 and is unlikely to work in Tahoe without modification.

tell application "System Events"
    tell application process "Control Center"
        -- Prepare UI element references.
        set wifi_menu_bar_item_ref to a reference to (first menu bar item of menu bar 1 whose value of attribute "AXIdentifier" is "com.apple.menuextra.wifi")
        set wifi_enabled_toggle_ref to a reference to (value of checkbox 1 of group 1 of window "Control Center")
        set wifi_connected_toggle_ref to a reference to (last checkbox of UI element 1 of scroll area 1 of group 1 of window "Control Center" where its value is true and value of its attribute "AXIdentifier" starts with "wifi-network-")
        set ssid_identifier_ref to a reference to (value of attribute "AXIdentifier" of wifi_connected_toggle_ref)
        
        -- Open the WiFi menu if it's not already open.
        if not (exists wifi_enabled_toggle_ref) then
            click wifi_menu_bar_item_ref
            delay 0.01 -- Just in case; doesn't appear necessary in testing.
        end if
        
        -- Get the SSID.
        set wifi_enabled to contents of wifi_enabled_toggle_ref as boolean
        if wifi_enabled then
            if exists wifi_connected_toggle_ref then
                set ssid_identifier to contents of ssid_identifier_ref
                set ssid to text 14 thru -1 of ssid_identifier
            else -- WiFi disconnected.
                set ssid to ""
            end if
        else -- WiFi disabled.
            set ssid to ""
        end if
        
        -- Close the WiFi menu.
        click wifi_menu_bar_item_ref
        
        -- Return the ssid.
        return ssid
    end tell
end tell

Note that this requires the WiFi menu bar item to be always visible.

The BSSID has similarly been restricted (prior to macOS 15.6); here's a version of the above GUI AppleScript that retrieves the BSSID (without needing sudo):

tell application "System Events"
    tell application process "Control Center"
        -- Prepare UI element references.
        set wifi_menu_bar_item_ref to a reference to (first menu bar item of menu bar 1 whose value of attribute "AXIdentifier" is "com.apple.menuextra.wifi")
        set wifi_enabled_toggle_ref to a reference to (value of checkbox 1 of group 1 of window "Control Center")
        set menu_buttons_group_ref to a reference to (group 1 of window "Control Center")
        set bssid_label_ref to a reference to (static text "BSSID:" of UI element 1 of scroll area 1 of group 1 of window "Control Center")
        set bssid_ref to a reference to (value of static text after static text after bssid_label_ref)
        
        -- Open the secondary WiFi menu if it's not already open.
        set some_menu_open to (exists wifi_enabled_toggle_ref)
        set secondary_menu_open to some_menu_open and (count buttons of menu_buttons_group_ref) is 4
        set primary_menu_open to some_menu_open and not secondary_menu_open
        if primary_menu_open then
            click wifi_menu_bar_item_ref -- Close the primary menu.
            delay 1.5
        end if
        if not secondary_menu_open then
            key down option
            click wifi_menu_bar_item_ref -- Open the secondary menu.
            key up option
            delay 0.01 -- Just in case; doesn't appear necessary in testing.
        end if
        
        -- Get the BSSID.
        if (exists bssid_label_ref) then
            set bssid to contents of bssid_ref
        else -- WiFi disconnected/disabled.
            if contents of wifi_enabled_toggle_ref as boolean then -- WiFi disconnected.
                set bssid to "00:00:00:00:00:00"
            else -- WiFi disabled.
                set bssid to "00:00:00:00:00:00"
            end if
        end if
        
        -- Close the WiFi menu.
        click wifi_menu_bar_item_ref
        
        -- Return the ssid.
        return bssid
    end tell
end tell
Sign up to request clarification or add additional context in comments.

12 Comments

Thank you so much! Sequoia broke the SSID retrieval part of my Automator script to set Wi-Fi network configuration specifically required in my workplace. I just changed the script based on your suggestions and hope to see it works tomorrow.
Aside: There's unfortunately no solution I've come across to getting the BSSID in macOS 15 Sequoia… It can be pulled from the WiFi menu (requiring an option-click) with GUI scripting, but there's no direct CLI access.
I'm not pretty sure about this: as far as I know, some open source repositories just directly assume eth0 as the WiFi adapter to simplify this process, but your code tries to find this adapter by itself, so is there a special situation that eth0 isn't a WiFi adapter or there are many WiFi adapters that you have considered? Thank you.
I believe some models have the built-in en0/en1 identifiers reversed for WiFi & ethernet. I can't give you a list off-hand, but I remember googling this issue after in came up on one of my machines (i.e. I didn't add code to search for the interface identifier "just because").
In my case, it was a 2019 27" iMac, which uses en1 for whatever reason.
not working on macOS 15.6
|
5

As posted here: Apple Forum

and here: Ask Different

Sequoia broke something when you try to retrieve the SSID. Currently, the only available solution is to use this:

system_profiler SPAirPortDataType | awk '/Current Network/ {getline;$1=$1;print $0 | "tr -d ':'";exit}'

That integrated into Swift becomes this:

import Foundation

func getWiFiNetworkName() -> String {
    let process = Process()
    process.executableURL = URL(fileURLWithPath: "/bin/bash")
    process.arguments = ["-c", "system_profiler SPAirPortDataType | awk '/Current Network/ {getline;$1=$1;print $0 | \"tr -d \':\'\";exit}'"]

    let pipe = Pipe()
    process.standardOutput = pipe

    do {
        try process.run()
    } catch {
        return "Error executing process."
    }

    let data = pipe.fileHandleForReading.readDataToEndOfFile()
    let output = String(data: data, encoding: .utf8)?.trimmingCharacters(in: .whitespacesAndNewlines)

    return output ?? "No Wi-Fi network detected."
}

let networkName = getWiFiNetworkName()
print("Connected to: \(networkName)")

If I find a better solution, I will update this post with the new one.

1 Comment

It works, but the system_profiler SPAirPortDataType command is so slow! you can get a little bit less verbose output, by using system_profiler SPAirPortDataType -detailLevel basic, but the command still takes a few seconds. The full command would then be: system_profiler SPAirPortDataType -detailLevel basic | awk '/Current Network/ {getline;$1=$1;print $0 | "tr -d ':'";exit}'
0

Here is a method to retrieve the Wi-Fi SSID using a bash script: MacOS: 15.3 (24D60) I tested a lot of methods and it worked

(ipconfig getsummary "$(networksetup -listallhardwareports | awk '/Wi-Fi|AirPort/{getline; print $NF}')" | grep ' SSID : ' | awk -F ': ' '{print $2}')

Here is a method to retrieve the Wi-Fi SSID using a bash script:

#!/bin/bash
# Get the name of the Wi-Fi interface
wifi_interface=$(networksetup -listallhardwareports | awk '/Wi-Fi|AirPort/{getline; print $2}')
echo "Debug: Wi-Fi Interface: $wifi_interface"  # Debug statement

# Use networksetup to get the SSID
if [ -n "$wifi_interface" ]; then
    wifi_name=$(ipconfig getsummary "$(networksetup -listallhardwareports | awk '/Wi-Fi|AirPort/{getline; print $NF}')" | grep ' SSID : ' | awk -F ': ' '{print $2}')
    echo "Debug: Wi-Fi Name: $wifi_name"  # Debug statement
else
    echo "Debug: No Wi-Fi interface found."  # Debug statement for when no interface is detected
fi

Output:

Debug: Wi-Fi Name: This_Is_real_wifi_name

This script retrieves the current Wi-Fi SSID by first identifying the Wi-Fi interface and then using ipconfig to get the SSID associated with that interface. The debug statements help trace the values being processed.

Comments

0

See caveats above regarding macOS ≥15.6.

Here is the swift function wrapped @David P.'s answer and @dot1q's answer.

func getCurrentWiFiSSID(interfaceName:String? = "en0") -> String? {
    var command = "";
    if(interfaceName == nil){
        command = #"networksetup -listallhardwareports | awk '/Wi-Fi|AirPort/{getline; print $NF}' | xargs ipconfig getsummary"#
    }
    else{
        command = "ipconfig getsummary \(interfaceName ?? "en0")"
    }
    command += #" | awk -F ' SSID : '  '/ SSID : / {print $2}'"#
    let process = Process()
    let pipe = Pipe()
    process.standardOutput = pipe
    process.standardError = pipe
    process.arguments = ["-c", command]
    process.launchPath = "/bin/bash"
    
    
    process.launch()
    process.waitUntilExit()
    
    let data = pipe.fileHandleForReading.readDataToEndOfFile()
    guard let output = String(data: data, encoding: .utf8)?
        .trimmingCharacters(in: .whitespacesAndNewlines),
          !output.isEmpty else {
        return nil
    }
    
    return output
}

As far as I know, the device en0 is usually a WiFi adapter device (and some open source code do the same), so if you call the function directly, it will skip the WiFi adapter seeking process and earn a better performance. You can call this function with getCurrentWiFiSSID(interfaceName: nil) to reproduce the process in @David P.'s answer.

1 Comment

On my 2019 27" iMac, en0 is ethernet and en1 is WiFi (no idea why!). I added the check because I personally had issues with en0/en1 being swapped on some of my Macs. Here's the output of my networksetup -listallhardwareports: Hardware Port: Ethernet Device: en0 Ethernet Address: XX:XX:XX:XX:XX:XX Hardware Port: Thunderbolt Bridge Device: bridge0 Ethernet Address: XX:XX:XX:XX:XX:XX Hardware Port: Wi-Fi Device: en1 Ethernet Address: XX:XX:XX:XX:XX:XX ...

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.