Getting WIFI SSID

Greetings

I'm trying to get on iPad the SSID from the wifi I'm connected to. For that, I added the wifi entitlement and I'm requesting permission to the user for Location.

Once I have it, I'm using the function CNCopySupportedInterfaces to get the interfaces, but I can only receive the en0, which using the method CNCopyCurrentNetworkInfo returns nil.

I also tried using the NEHotspotNetwork.fetchCurrent and the SSID keeps being nil. So right now I'm drawing a blank. Is there any way to make it work? Thanks.

Answered by DTS Engineer in 840106022

Don’t use CNCopySupportedInterfaces. It’s been deprecated in favour of NEHotspotNetwork.fetchCurrent(completionHandler:).

I’ve not had any problems getting fetchCurrent(completionHandler:) once I met the necessary criteria:

  • The device must actually be on Wi-Fi.

  • The app must be signed with the com.apple.developer.networking.wifi-info entitlement.

  • The app must be authorised by the user to access Wi-Fi information. The most obvious way to get that authorisation is via Core Location.

I just re-tested this with my test app running on iOS 18.4.1 and it worked as I remembered. At this end of this post you’ll find the model-level code for that test app. This relies on a fetchWiFiInfo(…) wrapper, because it needs to use different APIs on macOS and iOS. The iOS implementation of that wrapper looks like this:

enum WiFiInfo {

    static func fetchWiFiInfo(_ completionHandler: @escaping (_ ssid: String?) -> Void) {
        NEHotspotNetwork.fetchCurrent { networkQ in
            DispatchQueue.main.async {
                let ssid = networkQ?.ssid
                completionHandler(ssid)
            }
        }
    }
}

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"


class Model: NSObject, ObservableObject, CLLocationManagerDelegate {

    init(shouldStart: Bool = false) {
        self.logger = Logger(subsystem: "com.example.apple-samplecode.QCurrentSSID", category: "model")
        self.logger.log("init")
        super.init()
        if shouldStart {
            self.locationManager.delegate = self
            self.refreshSSID()
        }
    }
    
    private let logger: Logger

    // MARK: - SSID
    
    @Published var ssid: String?
    
    @Published var isRefreshingSSID: Bool = false
    
    func refreshSSID() {
        precondition( !self.isRefreshingSSID )
        self.logger.log("will refresh SSID")
        self.isRefreshingSSID = true
        WiFiInfo.fetchWiFiInfo() { ssid in
            self.ssid = ssid
            self.logger.log("did refresh SSID, ssid: \(ssid ?? "-", privacy: .private)")
            self.isRefreshingSSID = false
        }
    }

    // MARK: - Location

    @Published var locationState: LocationState = .notRequested
    
    enum LocationState {
        case notRequested
        case unknown
        case restricted
        case denied
        case authorised
        
        var canRequestLocation: Bool {
            switch self {
            case .notRequested: return true
            case .unknown:      return true
            case .restricted:   return false
            case .denied:       return false
            case .authorised:   return false
            }
        }
    }
    
    @Published var isRequestingLocation: Bool = false

    private let locationManager = CLLocationManager()
    
    func requestLocation() {
        precondition( !self.isRequestingLocation )
        self.logger.log("will request location")
        self.isRequestingLocation = true
        self.locationManager.requestWhenInUseAuthorization()
    }
    
    func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
        precondition(Thread.isMainThread)
        
        let newState: LocationState
        switch self.locationManager.authorizationStatus {
        case .notDetermined:       newState = .unknown
        case .restricted:          newState = .restricted
        case .denied:              newState = .denied
        case .authorizedAlways:    newState = .authorised
        case .authorizedWhenInUse: newState = .authorised
        @unknown default:          newState = .unknown
        }
        
        if newState != self.locationState {
            self.locationState = newState
            self.logger.log("did update location, state: \(".\(newState)", privacy: .public)")
            if !self.isRefreshingSSID {
                self.refreshSSID()
            }
        }
        if self.isRequestingLocation {
            self.isRequestingLocation = false
            self.logger.log("did request location")
        }
    }
}

Don’t use CNCopySupportedInterfaces. It’s been deprecated in favour of NEHotspotNetwork.fetchCurrent(completionHandler:).

I’ve not had any problems getting fetchCurrent(completionHandler:) once I met the necessary criteria:

  • The device must actually be on Wi-Fi.

  • The app must be signed with the com.apple.developer.networking.wifi-info entitlement.

  • The app must be authorised by the user to access Wi-Fi information. The most obvious way to get that authorisation is via Core Location.

I just re-tested this with my test app running on iOS 18.4.1 and it worked as I remembered. At this end of this post you’ll find the model-level code for that test app. This relies on a fetchWiFiInfo(…) wrapper, because it needs to use different APIs on macOS and iOS. The iOS implementation of that wrapper looks like this:

enum WiFiInfo {

    static func fetchWiFiInfo(_ completionHandler: @escaping (_ ssid: String?) -> Void) {
        NEHotspotNetwork.fetchCurrent { networkQ in
            DispatchQueue.main.async {
                let ssid = networkQ?.ssid
                completionHandler(ssid)
            }
        }
    }
}

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"


class Model: NSObject, ObservableObject, CLLocationManagerDelegate {

    init(shouldStart: Bool = false) {
        self.logger = Logger(subsystem: "com.example.apple-samplecode.QCurrentSSID", category: "model")
        self.logger.log("init")
        super.init()
        if shouldStart {
            self.locationManager.delegate = self
            self.refreshSSID()
        }
    }
    
    private let logger: Logger

    // MARK: - SSID
    
    @Published var ssid: String?
    
    @Published var isRefreshingSSID: Bool = false
    
    func refreshSSID() {
        precondition( !self.isRefreshingSSID )
        self.logger.log("will refresh SSID")
        self.isRefreshingSSID = true
        WiFiInfo.fetchWiFiInfo() { ssid in
            self.ssid = ssid
            self.logger.log("did refresh SSID, ssid: \(ssid ?? "-", privacy: .private)")
            self.isRefreshingSSID = false
        }
    }

    // MARK: - Location

    @Published var locationState: LocationState = .notRequested
    
    enum LocationState {
        case notRequested
        case unknown
        case restricted
        case denied
        case authorised
        
        var canRequestLocation: Bool {
            switch self {
            case .notRequested: return true
            case .unknown:      return true
            case .restricted:   return false
            case .denied:       return false
            case .authorised:   return false
            }
        }
    }
    
    @Published var isRequestingLocation: Bool = false

    private let locationManager = CLLocationManager()
    
    func requestLocation() {
        precondition( !self.isRequestingLocation )
        self.logger.log("will request location")
        self.isRequestingLocation = true
        self.locationManager.requestWhenInUseAuthorization()
    }
    
    func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
        precondition(Thread.isMainThread)
        
        let newState: LocationState
        switch self.locationManager.authorizationStatus {
        case .notDetermined:       newState = .unknown
        case .restricted:          newState = .restricted
        case .denied:              newState = .denied
        case .authorizedAlways:    newState = .authorised
        case .authorizedWhenInUse: newState = .authorised
        @unknown default:          newState = .unknown
        }
        
        if newState != self.locationState {
            self.locationState = newState
            self.logger.log("did update location, state: \(".\(newState)", privacy: .public)")
            if !self.isRefreshingSSID {
                self.refreshSSID()
            }
        }
        if self.isRequestingLocation {
            self.isRequestingLocation = false
            self.logger.log("did request location")
        }
    }
}
Getting WIFI SSID
 
 
Q