2015-08-05 2 views
3

Возможно ли получить MAC-адрес с помощью Swift?Как получить MAC-адрес от OSX с помощью Swift

MAC-адрес является основным адресом для Wi-Fi или аэропорта.

Я пытаюсь сделать приложение OS X.

+0

Ну я попытался посмотреть в стороне api для Swift, чтобы узнать, есть ли упоминание о получении адреса mac. Но я видел только адрес NSHost.currentHost() и возвращает то, что не является адресом mac. Я также видел способ сделать это в IOS, но использует UIDevice, который не связан с приложениями OS X. – jimbob

+0

Для этого есть код C, но я не знаю, может ли swift интегрировать C. – jimbob

+0

Вы имеете в виду Objective-C, C и Objective-C - это разные языки. –

ответ

1

ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ: не готовая продукция. Вероятно, это будет отклонено App Store. Это также подвержено ошибкам, если выход ifconfig изменится в будущем.Я сделал это, потому что мне не хватало навыков, чтобы перевести код C, указанный в ссылках. Он не заменяет полного решения Swift. Это, как говорится, это работает ...

Получить выход ifconfig «s и разобрать его, чтобы получить адрес MAC, связанный с интерфейсом (en0 в данном примере):

let theTask = NSTask() 
let taskOutput = NSPipe() 
theTask.launchPath = "/sbin/ifconfig" 
theTask.standardOutput = taskOutput 
theTask.standardError = taskOutput 
theTask.arguments = ["en0"] 

theTask.launch() 
theTask.waitUntilExit() 

let taskData = taskOutput.fileHandleForReading.readDataToEndOfFile() 

if let stringResult = NSString(data: taskData, encoding: NSUTF8StringEncoding) { 
    if stringResult != "ifconfig: interface en0 does not exist" { 
     let f = stringResult.rangeOfString("ether") 
     if f.location != NSNotFound { 
      let sub = stringResult.substringFromIndex(f.location + f.length) 
      let range = Range(start: advance(sub.startIndex, 1), end: advance(sub.startIndex, 18)) 
      let result = sub.substringWithRange(range) 
      println(result) 
     } 
    } 
} 
+0

Большое спасибо! Это намного лучше, чем работа, в которой я работал, которая выполняла эту команду bash: networksetup -listallhardwareports | grep -A 2 \ "Аппаратный порт: воздух \" | grep \ "Адрес Ethernet \" | cut -d \ ": \" -f2- – jimbob

4

Различный подход через if_msghdr

func MACAddressForBSD(bsd : String) -> String? 
{ 
    let MAC_ADDRESS_LENGTH = 6 
    let separator = ":" 

    var length : size_t = 0 
    var buffer : [CChar] 

    let BSDIndex = Int32(if_nametoindex(bsd)) 
    if BSDIndex == 0 { 
    println("Error: could not find index for bsd name \(bsd)") 
    return nil 
    } 
    let bsdData = bsd.dataUsingEncoding(NSUTF8StringEncoding)! 

    var managementInfoBase = [CTL_NET, AF_ROUTE, 0, AF_LINK, NET_RT_IFLIST, BSDIndex] 

    if sysctl(&managementInfoBase, 6, nil, &length, nil, 0) < 0 { 
    println("Error: could not determine length of info data structure"); 
    return nil; 
    } 

    buffer = [CChar](count: length, repeatedValue: 0) 

    if sysctl(&managementInfoBase, 6, &buffer, &length, nil, 0) < 0 { 
    println("Error: could not read info data structure"); 
    return nil; 
    } 

    let infoData = NSData(bytes: buffer, length: length) 
    var interfaceMsgStruct = if_msghdr() 
    infoData.getBytes(&interfaceMsgStruct, length: sizeof(if_msghdr)) 
    let socketStructStart = sizeof(if_msghdr) + 1 
    let socketStructData = infoData.subdataWithRange(NSMakeRange(socketStructStart, length - socketStructStart)) 
    let rangeOfToken = socketStructData.rangeOfData(bsdData, options: NSDataSearchOptions(0), range: NSMakeRange(0, socketStructData.length)) 
    let macAddressData = socketStructData.subdataWithRange(NSMakeRange(rangeOfToken.location + 3, MAC_ADDRESS_LENGTH)) 
    var macAddressDataBytes = [UInt8](count: MAC_ADDRESS_LENGTH, repeatedValue: 0) 
    macAddressData.getBytes(&macAddressDataBytes, length: MAC_ADDRESS_LENGTH) 
    let addressBytes = macAddressDataBytes.map({ String(format:"%02x", $0) }) 

    return join(separator, addressBytes) 
} 


MACAddressForBSD("en0") 
10

компании Apple пример кода из https://developer.apple.com/library/mac/samplecode/GetPrimaryMACAddress/Introduction/Intro.html для получения адреса Ethernet MAC может быть переведен на Swift. Я сохранил только самые важные комментарии , больше пояснений можно найти в исходном коде.

// 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) 
} 

Единственная «хитрая» часть, как работать с Unmanaged объектами, те имеют суффикс UM в моем коде.

Вместо того, чтобы возвращать код ошибки, функции возвращают необязательное значение , которое равно nil, если функция не удалась.


Обновление для 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) 
} 
+0

Мне было очень любопытно, что Swift перевод некоторых из особенностей C, в том числе, отличная работа;)! – Fantattitude

3

Обновление записи Мартина АиР. Существует несколько строк, которые не будут компилироваться с помощью Swift 2.1.

Изменение:

let matchingDict = matchingDictUM.takeUnretainedValue() as NSMutableDictionary 

To:

let matchingDict = matchingDictUM as NSMutableDictionary 

Изменение:

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

To:

let macAddressAsString = macAddress.map({ String(format:"%02x", $0) }).joinWithSeparator(":") 
Смежные вопросы