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

JB.
  • 40,344
  • 12
  • 79
  • 106
Oswaldo Rodriguez
  • 173
  • 1
  • 1
  • 12
  • Most probably, you can just remove the `take(Un)RetainedValue()` calls, because the function do not return unmanaged objects anymore in Swift 2. See http://stackoverflow.com/questions/30740000/withunsafepointer-in-swift-2 for a similar Q&A. – Martin R Sep 11 '15 at 15:27
  • i deleted the .takeRetainedValue() but now im getting an EXC_BREAKPOINT (EXC_ARM_BREAKPOINT, subcode=0xe7ffdefe) when i try to test the code – Oswaldo Rodriguez Sep 11 '15 at 18:57
  • Unfortunately I cannot help you with that. I do not have a captive network to test the code. – Martin R Sep 11 '15 at 19:09
  • dont worry, thanks anyways – Oswaldo Rodriguez Sep 11 '15 at 19:13
  • 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! – JB. Sep 13 '15 at 16:19

10 Answers10

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
    }
}
Khaled Annajar
  • 15,542
  • 5
  • 34
  • 45
RikiRiocma
  • 746
  • 12
  • 28
  • Keep in mind that `CNCopySupportedInterfaces` returns nil on simulator. You should therefore check if `interfaces` is not nil. – Fogh Sep 25 '15 at 08:30
  • 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) – RikiRiocma Sep 25 '15 at 14:10
  • It is much simpler to just say: `if let interfaces:CFArray! = CNCopySupportedInterfaces()` – Fogh Sep 27 '15 at 13:42
  • 3
    Note that CaptiveNetwork was deprecated in iOS 9.0. So I would suggest using an alternative solution. – Matt Le Fleur Oct 08 '15 at 14:21
  • The code works for my iOS 9 project although Xcode has deprecate warnings. – oOEric Jan 19 '16 at 02:53
  • 3
    No longer deprecated in iOS 10 http://stackoverflow.com/a/33132529/2865234 @MattLeFleur – Emin Israfil iOS Jul 26 '16 at 20:59
  • 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? – Robert Aug 18 '16 at 14:31
  • @RikiRiocma :- 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. – Sagar Aug 15 '19 at 03:39
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

Daniyar
  • 2,975
  • 2
  • 26
  • 39
Rob
  • 2,649
  • 3
  • 27
  • 34
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
}
werediver
  • 4,667
  • 1
  • 29
  • 49
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 
Doug
  • 794
  • 7
  • 12
Japes
  • 393
  • 5
  • 11
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
}
alegelos
  • 2,308
  • 17
  • 26
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
}

}

Wei Wen Hsiao
  • 191
  • 1
  • 17
  • This code doesn't compile under iOS 9.2. It still uses a version of takeRetainedValue() that isn't available any longer. – mbeaty Jan 13 '16 at 03:30
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.

Cameron Lowell Palmer
  • 21,528
  • 7
  • 125
  • 126
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

Ahmed Lotfy
  • 3,806
  • 26
  • 28
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
    }
7ball
  • 2,183
  • 4
  • 26
  • 61
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
    }

}
abdullahselek
  • 7,893
  • 3
  • 50
  • 40