是否可以使用Swift获取MAC地址?
MAC地址是Wi-Fi或机场的主要地址。
我正在尝试制作OS X应用程序。
答案 0 :(得分:13)
Apple的https://developer.apple.com/library/mac/samplecode/GetPrimaryMACAddress/Introduction/Intro.html示例代码可以检索以太网MAC地址 被翻译成斯威夫特。我只保留了最重要的 评论,更多解释可以在原始代码中找到。
// 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)
}
答案 1 :(得分: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")
答案 2 :(得分:3)
更新Martin R的条目。有几行不能用Swift 2.1编译。
变化:
let matchingDict = matchingDictUM.takeUnretainedValue() as NSMutableDictionary
要:
let matchingDict = matchingDictUM as NSMutableDictionary
变化:
let macAddressAsString = ":".join(macAddress.map( { String(format:"%02x", $0) } ))
要:
let macAddressAsString = macAddress.map( { String(format:"%02x", $0) } ).joinWithSeparator(":")
答案 3 :(得分:2)
针对Swift 4.2的更新
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! 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, kIOServicePlane, &controllerService) == KERN_SUCCESS {
let dataUM = IORegistryEntryCreateCFProperty(controllerService, "IOMACAddress" as CFString, kCFAllocatorDefault, 0)
if dataUM != nil {
let data = (dataUM!.takeRetainedValue() as! CFData) as Data
macAddress = [0, 0, 0, 0, 0, 0]
data.copyBytes(to: &macAddress!, count: macAddress!.count)
}
IOObjectRelease(controllerService)
}
IOObjectRelease(intfService)
intfService = IOIteratorNext(intfIterator)
}
return macAddress
}
func getMacAddress() -> String? {
var macAddressAsString : String?
if let intfIterator = FindEthernetInterfaces() {
if let macAddress = GetMACAddress(intfIterator) {
macAddressAsString = macAddress.map( { String(format:"%02x", $0) } ).joined(separator: ":")
print(macAddressAsString!)
}
IOObjectRelease(intfIterator)
}
return macAddressAsString
}
答案 4 :(得分:1)
您也可以使用“系统配置”框架
import SystemConfiguration
func collectMACAddresses() -> [String] {
guard let interfaces = SCNetworkInterfaceCopyAll() as? [SCNetworkInterface] else {
return []
}
return interfaces
.map(SCNetworkInterfaceGetHardwareAddressString)
.compactMap { $0 as String? }
}
答案 5 :(得分:0)
免责声明:这是不生产就绪。它可能会被App Store拒绝。如果ifconfig
的输出在将来发生变化,它也会出错。 我之所以这样做是因为我缺乏翻译C代码的技能。链接。它不能取代完整的Swift解决方案。话虽如此,它有效......
获取ifconfig
的输出并解析它以获取与接口关联的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)
}
}
}