Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
981 views
in Technique[技术] by (71.8m points)

macos - How to get MAC address from OS X with Swift

Is it possible to get the MAC address using Swift?

The MAC address being the primary address for the Wi-Fi or Airport.

I'm trying to make a OS X application.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Apple's sample code from https://developer.apple.com/library/mac/samplecode/GetPrimaryMACAddress/Introduction/Intro.html to retrieve the Ethernet MAC address can be translated to Swift. I have preserved only the most important comments, more explanations can be found in the original code.

// Returns an iterator containing the primary (built-in) Ethernet interface. The caller is responsible for
// releasing the iterator after the caller is done with it.
func FindEthernetInterfaces() -> io_iterator_t? {

    let matchingDictUM = IOServiceMatching("IOEthernetInterface");
    // Note that another option here would be:
    // matchingDict = IOBSDMatching("en0");
    // but en0: isn't necessarily the primary interface, especially on systems with multiple Ethernet ports.

    if matchingDictUM == nil {
        return nil
    }
    let matchingDict = matchingDictUM.takeUnretainedValue() as NSMutableDictionary
    matchingDict["IOPropertyMatch"] = [ "IOPrimaryInterface" : true]

    var matchingServices : io_iterator_t = 0
    if IOServiceGetMatchingServices(kIOMasterPortDefault, matchingDict, &matchingServices) != KERN_SUCCESS {
        return nil
    }

    return matchingServices
}

// Given an iterator across a set of Ethernet interfaces, return the MAC address of the last one.
// If no interfaces are found the MAC address is set to an empty string.
// In this sample the iterator should contain just the primary interface.
func GetMACAddress(intfIterator : io_iterator_t) -> [UInt8]? {

    var macAddress : [UInt8]?

    var intfService = IOIteratorNext(intfIterator)
    while intfService != 0 {

        var controllerService : io_object_t = 0
        if IORegistryEntryGetParentEntry(intfService, "IOService", &controllerService) == KERN_SUCCESS {

            let dataUM = IORegistryEntryCreateCFProperty(controllerService, "IOMACAddress", kCFAllocatorDefault, 0)
            if dataUM != nil {
                let data = dataUM.takeRetainedValue() as! NSData
                macAddress = [0, 0, 0, 0, 0, 0]
                data.getBytes(&macAddress!, length: macAddress!.count)
            }
            IOObjectRelease(controllerService)
        }

        IOObjectRelease(intfService)
        intfService = IOIteratorNext(intfIterator)
    }

    return macAddress
}


if let intfIterator = FindEthernetInterfaces() {
    if let macAddress = GetMACAddress(intfIterator) {
        let macAddressAsString = ":".join(macAddress.map( { String(format:"%02x", $0) } ))
        println(macAddressAsString)
    }

    IOObjectRelease(intfIterator)
}

The only "tricky" part is how to work with Unmanaged objects, those have the suffix UM in my code.

Instead of returning an error code, the functions return an optional value which is nil if the function failed.


Update for Swift 3:

func FindEthernetInterfaces() -> io_iterator_t? {

    let matchingDict = IOServiceMatching("IOEthernetInterface") as NSMutableDictionary
    matchingDict["IOPropertyMatch"] = [ "IOPrimaryInterface" : true]

    var matchingServices : io_iterator_t = 0
    if IOServiceGetMatchingServices(kIOMasterPortDefault, matchingDict, &matchingServices) != KERN_SUCCESS {
        return nil
    }

    return matchingServices
}

func GetMACAddress(_ intfIterator : io_iterator_t) -> [UInt8]? {

    var macAddress : [UInt8]?

    var intfService = IOIteratorNext(intfIterator)
    while intfService != 0 {

        var controllerService : io_object_t = 0
        if IORegistryEntryGetParentEntry(intfService, "IOService", &controllerService) == KERN_SUCCESS {

            let dataUM = IORegistryEntryCreateCFProperty(controllerService, "IOMACAddress" as CFString, kCFAllocatorDefault, 0)
            if let data = dataUM?.takeRetainedValue() as? NSData {
                macAddress = [0, 0, 0, 0, 0, 0]
                data.getBytes(&macAddress!, length: macAddress!.count)
            }
            IOObjectRelease(controllerService)
        }

        IOObjectRelease(intfService)
        intfService = IOIteratorNext(intfIterator)
    }

    return macAddress
}

if let intfIterator = FindEthernetInterfaces() {
    if let macAddress = GetMACAddress(intfIterator) {
        let macAddressAsString = macAddress.map( { String(format:"%02x", $0) } )
            .joined(separator: ":")
        print(macAddressAsString)
    }

    IOObjectRelease(intfIterator)
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...