shreddish shreddish - 3 months ago 46
Swift Question

Swift CNCopySupportedInterfaces not valid

Trying to get the SSID of current device. I have found plenty of examples on how to do it however I am struggling with getting the CNCopySupportedInterfaces to autocomplete. I have 'import SystemConfiguration' at the top of my swift file but no success. Can't seem to figure out what I am doing wrong.

Answer

You need import SystemConfiguration.CaptiveNetwork

Underneath the covers, CaptiveNetwork is a C header file (.h) that is within the SystemConfiguration framework:

/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/System/Library/Frameworks/SystemConfiguration.framework/Headers/CaptiveNetwork.h

If you know Objective-C, this goes into more depth:

iPhone get SSID without private library

Also, auto-complete is not happy with legacy globals; it only wants classes at the top level. Probably because there are just too many @#$@# globals.

Oh, and you have to write this wonderful snippet to get it to work:

    for interface in CNCopySupportedInterfaces().takeRetainedValue() as! [String] {
        println("Looking up SSID info for \(interface)") // en0
        let SSIDDict = CNCopyCurrentNetworkInfo(interface).takeRetainedValue() as! [String : AnyObject]
        for d in SSIDDict.keys {
            println("\(d): \(SSIDDict[d]!)")
        }
    }

ADDENDUM FOR SWIFT 2.2

Bridging has been simplified for CFxxx datatypes and now unwrapping and a lot of ferrying is required but no retain calls. I don't know that Swift 2 has made things any easier but it's fairly clear what's going on, plus the nil helps us identify the simulator. The other answer (for Swift 3) uses an awful lot of bit-casting and unsafe operations which seems non-Swiftian, so I offer this. To make this Swift-3 friendly, remove NS everywhere.

    func getInterfaces() -> Bool {
        guard let unwrappedCFArrayInterfaces = CNCopySupportedInterfaces() else {
            print("this must be a simulator, no interfaces found")
            return false
        }
        guard let swiftInterfaces = (unwrappedCFArrayInterfaces as NSArray) as? [String] else {
            print("System error: did not come back as array of Strings")
            return false
        }
        for interface in swiftInterfaces {
            print("Looking up SSID info for \(interface)") // en0
            guard let unwrappedCFDictionaryForInterface = CNCopyCurrentNetworkInfo(interface) else {
                print("System error: \(interface) has no information")
                return false
            }
            guard let SSIDDict = (unwrappedCFDictionaryForInterface as NSDictionary) as? [String: AnyObject] else {
                print("System error: interface information is not a string-keyed dictionary")
                return false
            }
            for d in SSIDDict.keys {
                print("\(d): \(SSIDDict[d]!)")
            }
        }
        return true
    }

[Also, after 10 minutes, auto-complete started to work for CNxxx. Clearly a background thread is busily digesting thousands of globals in SourceKit.]

Output on success:

SSIDDATA: <57696c6d 79>

BSSID: 12:34:56:78:9a:bc

SSID: YourSSIDHere