Get SSID in Swift 2
Asked Answered
B

10

15

Im trying to use this code to get SSID

import Foundation
import SystemConfiguration.CaptiveNetwork

public class SSID {
    class func getSSID() -> String{
        var currentSSID = ""
        let interfaces = CNCopySupportedInterfaces()
        if interfaces != nil {
            let interfacesArray = interfaces.takeRetainedValue() as [String : AnyObject]
            if interfacesArray.count > 0 {
                let interfaceName = interfacesArray[0] as String
                let unsafeInterfaceData = CNCopyCurrentNetworkInfo(interfaceName)
                if unsafeInterfaceData != nil {
                    let interfaceData = unsafeInterfaceData.takeRetainedValue() as Dictionary!
                    currentSSID = interfaceData[kCNNetworkInfoKeySSID] as! String
                    let ssiddata = NSString(data:interfaceData[kCNNetworkInfoKeySSIDData]! as! NSData, encoding:NSUTF8StringEncoding) as! String
                    // ssid data from hex
                    print(ssiddata)
                }
            }
        }
        return currentSSID
    }
}

But in getting an error in this line let interfacesArray = interfaces.takeRetainedValue() as [String : AnyObject]

The error is

Value of type 'CFArray?' has no member 'takeRetainedValue'

Thanks for your help

Brockie answered 11/9, 2015 at 15:17 Comment(5)
Most probably, you can just remove the take(Un)RetainedValue() calls, because the function do not return unmanaged objects anymore in Swift 2. See #30740500 for a similar Q&A.Caprifoliaceous
i deleted the .takeRetainedValue() but now im getting an EXC_BREAKPOINT (EXC_ARM_BREAKPOINT, subcode=0xe7ffdefe) when i try to test the codeBrockie
Unfortunately I cannot help you with that. I do not have a captive network to test the code.Caprifoliaceous
dont worry, thanks anywaysBrockie
Welcome to StackOverflow! I've formatted your code so it fits in a normal window; but you might want to give it another pass for the very long lines there. Good luck!Edelmiraedelson
S
27

This may help you (tested on Swift 2):

import Foundation
import SystemConfiguration.CaptiveNetwork

public class SSID {
    class func fetchSSIDInfo() -> String {
        var currentSSID = ""
        if let interfaces = CNCopySupportedInterfaces() {
            for i in 0..<CFArrayGetCount(interfaces) {
                let interfaceName: UnsafePointer<Void> = CFArrayGetValueAtIndex(interfaces, i)
                let rec = unsafeBitCast(interfaceName, AnyObject.self)
                let unsafeInterfaceData = CNCopyCurrentNetworkInfo("\(rec)")
                if unsafeInterfaceData != nil {
                    let interfaceData = unsafeInterfaceData! as Dictionary!
                    currentSSID = interfaceData["SSID"] as! String
                }
            }
        }
        return currentSSID
    }
}

I took and adapted the code from Ray Wenderlich's site (once was here: Retrieve SSID in iOS9 but now the specific thread has been removed from site)

iOS 12

You must enable Access WiFi Information from capabilities.

Important To use this function in iOS 12 and later, enable the Access WiFi Information capability for your app in Xcode. When you enable this capability, Xcode automatically adds the Access WiFi Information entitlement to your entitlements file and App ID. Documentation link

Swift4.2

public class SSID {
    class func fetchSSIDInfo() -> String {
        var currentSSID = ""
        if let interfaces = CNCopySupportedInterfaces() {
            for i in 0..<CFArrayGetCount(interfaces) {
                let interfaceName: UnsafeRawPointer = CFArrayGetValueAtIndex(interfaces, i)
                let rec = unsafeBitCast(interfaceName, to: AnyObject.self)
                let unsafeInterfaceData = CNCopyCurrentNetworkInfo("\(rec)" as CFString)
                if let interfaceData = unsafeInterfaceData as? [String: AnyObject] {
                    currentSSID = interfaceData["SSID"] as! String
                    let BSSID = interfaceData["BSSID"] as! String
                    let SSIDDATA = interfaceData["SSIDDATA"] as! String
                    debugPrint("ssid=\(currentSSID), BSSID=\(BSSID), SSIDDATA=\(SSIDDATA)")
                }
            }
        }
        return currentSSID
    }
}
Stronghold answered 24/9, 2015 at 17:40 Comment(8)
Keep in mind that CNCopySupportedInterfaces returns nil on simulator. You should therefore check if interfaces is not nil.Carl
Yes, actually I have not considered this possibility. Maybe is better check if app is running within the simulator, and return a "fake" SSID in this case (see macro #if TARGET_IPHONE_SIMULATOR)Stronghold
It is much simpler to just say: if let interfaces:CFArray! = CNCopySupportedInterfaces()Carl
Note that CaptiveNetwork was deprecated in iOS 9.0. So I would suggest using an alternative solution.Cystocele
The code works for my iOS 9 project although Xcode has deprecate warnings.Detection
No longer deprecated in iOS 10 https://mcmap.net/q/151089/-iphone-get-ssid-without-private-library @MattLeFleurDistrait
I've very occasionally noticed crash reports come through which happen on CFArrayGetCount. I then noticed you were casting interfaces to an optional in the if let, which to my surprise appears to enter the if statement even if CNCopySupportedInterfaces() returns nil. Should it not be if let interfaces = CNCopySupportedInterfaces(), which I think would fix that?Robbinrobbins
@Stronghold :- Just an small update, the above code crash at the line 'let SSIDDATA = interfaceData["SSIDDATA"] as! String' Instead use 'let SSIDDATA = interfaceData["SSIDDATA"] as? [[String : AnyObject]] ?? [] ' works well with same value output.Evangelin
A
14

This is my solution Swift 3 iOS 10 and it works well with Xcode 8

import Foundation

import SystemConfiguration.CaptiveNetwork

class network : NSObject {

    func getSSID() -> String? {

        let interfaces = CNCopySupportedInterfaces()
        if interfaces == nil {
            return nil
        }

        let interfacesArray = interfaces as! [String]
        if interfacesArray.count <= 0 {
            return nil
        }

        let interfaceName = interfacesArray[0] as String
        let unsafeInterfaceData =     CNCopyCurrentNetworkInfo(interfaceName as CFString)
        if unsafeInterfaceData == nil {
            return nil
        }

        let interfaceData = unsafeInterfaceData as! Dictionary <String,AnyObject>

        return interfaceData["SSID"] as? String
    }

}

To use it:

let wifiName = network().getSSID()

    guard wifiName != nil else {

        //// TODO: Alert -----
        print("no wifi name")

        return
    }


    print("my network name is: \(wifiName!)")

PS: Attention it not works on simulator

Ambagious answered 18/9, 2016 at 8:13 Comment(1)
This works perfect in iOS 10, using Swift 3. Thanks!!Tops
C
8

All the presented at the moment solutions seems rather complex, with ugly unsafe casts.

I was able to craft such a concise solution (with no black magic at all):

import Foundation
import SystemConfiguration.CaptiveNetwork

func getSSID() -> String? {
    var ssid: String?
    if let interfaces = CNCopySupportedInterfaces() as NSArray? {
        for interface in interfaces {
            if let interfaceInfo = CNCopyCurrentNetworkInfo(interface as! CFString) as NSDictionary? {
                ssid = interfaceInfo[kCNNetworkInfoKeySSID as String] as? String
                break
            }
        }
    }
    return ssid
}
Carollcarolle answered 16/6, 2016 at 10:25 Comment(2)
"CNCopySupportedInterfaces" Deprecated in iOS 9.0.Abuse
Yet we have no other options (discussed here and many times on the SO).Carollcarolle
H
5

In Swift 3 (works in real device and simulator):

import SystemConfiguration.CaptiveNetwork

internal class SSID {
    class func fetchSSIDInfo() ->  String {
        var currentSSID = ""
        if let interfaces:CFArray = CNCopySupportedInterfaces() {
            for i in 0..<CFArrayGetCount(interfaces){
                let interfaceName: UnsafeRawPointer = CFArrayGetValueAtIndex(interfaces, i)
                let rec = unsafeBitCast(interfaceName, to: AnyObject.self)
                let unsafeInterfaceData = CNCopyCurrentNetworkInfo("\(rec)" as CFString)
                if unsafeInterfaceData != nil {

                    let interfaceData = unsafeInterfaceData! as Dictionary!
                    currentSSID = ((interfaceData as? [String : AnyObject])?["SSID"])! as! String

                }
            }
        }
        return currentSSID
    }
}

Usage:

SSID.fetchSSIDInfo()

//will return "" if no connected wifi or running in simulator 
Hydrofoil answered 11/10, 2016 at 19:21 Comment(0)
B
2

Swift 4 version

import SystemConfiguration.CaptiveNetwork


func getSSID() -> String? {
    guard let interface = (CNCopySupportedInterfaces() as? [String])?.first,
        let unsafeInterfaceData = CNCopyCurrentNetworkInfo(interface as CFString) as? [String: Any],
        let ssid = unsafeInterfaceData["SSID"] as? String else{
            return nil
    }
    return ssid
}
Buxton answered 24/7, 2018 at 13:33 Comment(5)
I always get nil value for my WIFI. How to fix this?Ablaut
did u enable Access WiFi Information from capabilities?Buxton
My account cant enable "Access WIFI Information" from capabilities.Ablaut
Did you try this? izziswift.com/wp-content/uploads/2019/03/…Buxton
As of iOS13, the user has to allow location services as explained here: https://mcmap.net/q/153598/-ios-13-2-message-nehelper-sent-invalid-result-code-1-for-wi-fi-information-requestPass
B
1

In swift 2, you don't have to call takeRetainedValue.

Replace the code interfaces.takeRetainedValue() as [String : AnyObject] with Array(arrayLiteral: interfaces).

Also remember change the code interfacesArray[0] as String into String(interfacesArray[0]).

Full code :

public class SSID {
class func getSSID() -> String{
    var currentSSID = ""
    let interfaces = CNCopySupportedInterfaces()
    if interfaces != nil {
        let interfacesArray = Array(arrayLiteral: interfaces)
        if interfacesArray.count > 0 {
            let interfaceName =  String(interfacesArray[0])
            let unsafeInterfaceData = CNCopyCurrentNetworkInfo(interfaceName)
            if unsafeInterfaceData != nil {
                let interfaceData = unsafeInterfaceData.takeRetainedValue() as Dictionary!
                currentSSID = interfaceData[kCNNetworkInfoKeySSID] as! String
                let ssiddata = NSString(data:interfaceData[kCNNetworkInfoKeySSIDData]! as! NSData, encoding:NSUTF8StringEncoding) as! String
                // ssid data from hex
                print(ssiddata)
            }
        }
    }
    return currentSSID
}

}

Bashemeth answered 19/9, 2015 at 5:25 Comment(1)
This code doesn't compile under iOS 9.2. It still uses a version of takeRetainedValue() that isn't available any longer.Dharna
P
1

Grabbing WiFi Network SSID and BSSID in Swift

I have seen a lot of versions of this very popular question using the SystemConfiguration framework. Reading through this list of answers I've found that they're all over the place. Unsafe-bit casting, magic strings, weird coercion. Any time an API returns CFArray or CFDictionary use toll-free bridging to get an NS{Array,Dictionary}. It allows you to avoid some of the uglier aspects (in the context of Swift) of CoreFoundation. Also you should use the constants defined in the header for the SSID and BSSID dictionary values. Absolutely no need for the Unsafe types here, all of the data types are well-defined. That said, the CaptiveNetwork version of this code is deprecated in iOS 14 and it is recommended you use the NetworkExtension framework instead.

NEHotspotNetwork

import NetworkExtension

NEHotspotNetwork.fetchCurrent { hotspotNetwork in
    if let ssid = hotspotNetwork?.ssid {
        print(ssid)
    }
}

Deprecated - CaptiveNetwork Method

import SystemConfiguration.CaptiveNetwork

func getWiFiNetwork() -> (ssid: String, bssid: String)?
{
    var wifiNetwork: (ssid: String, bssid: String)?
    if let interfaces = CNCopySupportedInterfaces() as NSArray? {
        for interface in interfaces {
            let name = interface as! CFString
            if let interfaceData = CNCopyCurrentNetworkInfo(name) as NSDictionary? {
                if let ssid = interfaceData[kCNNetworkInfoKeySSID] as? String,
                    let bssid = interfaceData[kCNNetworkInfoKeyBSSID] as? String {
                    wifiNetwork = (ssid: ssid, bssid: bssid)
                }
            }
        }
    }
    
    return wifiNetwork
}

Permissions - CoreLocation

In terms of user permissions you have possibilities, but you need one of four defined in the documentation for CNCopyCurrentNetworkInfo or fetchCurrent - for most cases I assume you will need to add CoreLocation and ask for permission to use the user's location. For example, Privacy - Location When In Use Usage Description in the Info.plist needs a reason for why you require the user's location and then you must make the call to request the user authorization dialog.

    import CoreLocation

    CLLocationManager().requestWhenInUseAuthorization()

Entitlements

Your app also need the entitlement - com.apple.developer.networking.wifi-info which is added in Signing and Capabilities section of the project and is called Access WiFi Information. When using NEHotspotNetwork method there is an additional Network Extensions entitlement required.

Poul answered 4/12, 2020 at 8:44 Comment(0)
P
0

The following function return the wifi name and the Mac address

    func getNetworkInfo()->(success:Bool,ssid:String,mac:String){
      var currentSSID:String = ""
      var macAdrees:String = ""
      var succes:Bool = false
      let interfaces:CFArray! = CNCopySupportedInterfaces()
      for i in 0..<CFArrayGetCount(interfaces){
        let interfaceName: UnsafePointer<Void>
        =  CFArrayGetValueAtIndex(interfaces, i)
        let rec = unsafeBitCast(interfaceName, AnyObject.self)
        let unsafeInterfaceData = CNCopyCurrentNetworkInfo("\(rec)")
        if unsafeInterfaceData != nil {
            let interfaceData = unsafeInterfaceData! as Dictionary!
            currentSSID = interfaceData["SSID"] as! String
            macAdrees = interfaceData["BSSID"] as! String
            succes = true
        } else {
            currentSSID = ""
        }
    }

    return (succes, currentSSID, macAdrees)
}

This code works fine. You will note some warning in your development target >= iOS9

Peoria answered 23/3, 2016 at 16:21 Comment(0)
D
0

https://stackoverflow.com/users/3108877/rob's answer -- shorter version

func getSSID() -> String? {
        if let interface = (CNCopySupportedInterfaces() as? [String])?.first,
            let unsafeInterfaceData = CNCopyCurrentNetworkInfo(interface as CFString) as? [String: Any],
            let ssid = unsafeInterfaceData["SSID"] as? String {
            return ssid
        }
        return nil
    }
Dilapidated answered 18/7, 2017 at 6:5 Comment(0)
C
0

You can find an another answer with updated Swift standards of @japes answer which supports both Swift 3 and Swift 4. Return empty "" on simulators.

import SystemConfiguration.CaptiveNetwork

internal class SSID {

    class func fetchSSIDInfo() -> String {
        var currentSSID = ""
        if let interfaces = CNCopySupportedInterfaces() {
            for i in 0..<CFArrayGetCount(interfaces){
                let interfaceName = CFArrayGetValueAtIndex(interfaces, i)
                let rec = unsafeBitCast(interfaceName, to: AnyObject.self)
                guard let unsafeInterfaceData = CNCopyCurrentNetworkInfo("\(rec)" as CFString) else {
                    return currentSSID
                }
                guard let interfaceData = unsafeInterfaceData as? [String: Any] else {
                    return currentSSID
                }
                guard let SSID = interfaceData["SSID"] as? String else {
                    return currentSSID
                }
                currentSSID = SSID
            }
        }
        return currentSSID
    }

}
Centaurus answered 16/3, 2018 at 14:23 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.