Возможно ли получить MAC-адрес с помощью Swift?Как получить MAC-адрес от OSX с помощью Swift
MAC-адрес является основным адресом для Wi-Fi или аэропорта.
Я пытаюсь сделать приложение OS X.
Возможно ли получить MAC-адрес с помощью Swift?Как получить MAC-адрес от OSX с помощью Swift
MAC-адрес является основным адресом для Wi-Fi или аэропорта.
Я пытаюсь сделать приложение OS X.
ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ: не готовая продукция. Вероятно, это будет отклонено 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)
}
}
}
Большое спасибо! Это намного лучше, чем работа, в которой я работал, которая выполняла эту команду bash: networksetup -listallhardwareports | grep -A 2 \ "Аппаратный порт: воздух \" | grep \ "Адрес Ethernet \" | cut -d \ ": \" -f2- – jimbob
Различный подход через 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")
компании 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)
}
Мне было очень любопытно, что Swift перевод некоторых из особенностей C, в том числе, отличная работа;)! – Fantattitude
Обновление записи Мартина АиР. Существует несколько строк, которые не будут компилироваться с помощью 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(":")
Ну я попытался посмотреть в стороне api для Swift, чтобы узнать, есть ли упоминание о получении адреса mac. Но я видел только адрес NSHost.currentHost() и возвращает то, что не является адресом mac. Я также видел способ сделать это в IOS, но использует UIDevice, который не связан с приложениями OS X. – jimbob
Для этого есть код C, но я не знаю, может ли swift интегрировать C. – jimbob
Вы имеете в виду Objective-C, C и Objective-C - это разные языки. –