如何通过IP/MAC地址获取网络中苹果设备的Model Identifier?
问题解答
一、通用获取苹果设备Model Identifier的方法
苹果设备确实会通过_device-info._tcp这个Bonjour服务发布Model Identifier(如Macmini9,1),该服务在Ventura系统下完全可用——Finder就是依赖它获取设备专属图标和信息的。你之前的代码未收到TXT消息,主要是因为硬编码服务名称的方式不可靠,正确的做法是先通过NetServiceBrowser动态发现局域网内的_device-info._tcp服务,再解析对应服务的TXT记录。
修正后的代码示例
import Foundation class AppleDeviceInfoScanner: NSObject, NetServiceBrowserDelegate, NetServiceDelegate { private let browser = NetServiceBrowser() func startScanning() { browser.delegate = self // 搜索本地局域网内的_device-info._tcp服务 browser.searchForServices(ofType: "_device-info._tcp", inDomain: "local.") } // NetServiceBrowserDelegate:发现可用服务 func netServiceBrowser(_ browser: NetServiceBrowser, didFind service: NetService, moreComing: Bool) { service.delegate = self // 主动解析服务的地址和TXT记录,超时时间设为5秒 service.resolve(withTimeout: 5.0) } func netServiceBrowser(_ browser: NetServiceBrowser, didRemove service: NetService, moreComing: Bool) { // 处理设备离线逻辑(可选) } // NetServiceDelegate:解析成功,提取Model Identifier func netServiceDidResolveAddress(_ service: NetService) { guard let txtData = service.txtRecordData(), let txtDict = NetService.dictionary(fromTXTRecord: txtData) else { return } // Model Identifier存储在"model"键对应的TXT数据中 if let modelData = txtDict["model"], let modelId = String(data: modelData, encoding: .utf8) { print("设备名称:\(service.name) | Model Identifier:\(modelId)") } // 额外可提取的信息:设备类型ID(deviceid)、系统版本(osvers)等 if let osVersionData = txtDict["osvers"], let osVersion = String(data: osVersionData, encoding: .utf8) { print("系统版本:\(osVersion)") } } func netService(_ service: NetService, didNotResolve errorDict: [String : NSNumber]) { print("解析服务失败:\(service.name),错误信息:\(errorDict)") } } // 使用方式 let scanner = AppleDeviceInfoScanner() scanner.startScanning()
关键注意事项
- 权限配置:Ventura对局域网访问权限要求严格,必须在
Info.plist中添加以下配置:- 添加
NSBonjourServices数组,包含字符串_device-info._tcp - 添加
NSLocalNetworkUsageDescription字符串,说明局域网访问的用途(比如"用于发现局域网内的苹果设备信息")
- 添加
- 兼容性:大部分现代苹果设备(2013年后的Mac、iOS 10+的移动设备、Apple TV 4+)都会发布
_device-info._tcp服务,旧款设备可能不支持。
二、获取网络设备厂商名称的方法
厂商名称可通过MAC地址的**OUI(组织唯一标识符)**查询——MAC地址的前3字节是厂商的唯一标识。可以直接解析macOS系统内置的OUI数据库,无需依赖外部接口。
实现代码示例
func getDeviceVendor(from macAddress: String) -> String? { // macOS系统内置的OUI数据库路径 let ouiFileURL = URL(fileURLWithPath: "/usr/share/misc/oui.txt") guard let ouiContent = try? String(contentsOf: ouiFileURL) else { return nil } // 格式化MAC地址:去掉分隔符,提取前6位并转为大写 let cleanMacPrefix = macAddress.replacingOccurrences(of: ":", with: "") .replacingOccurrences(of: "-", with: "") .prefix(6) .uppercased() // 遍历OUI内容匹配厂商 for line in ouiContent.components(separatedBy: .newlines) { if line.contains(cleanMacPrefix) { let lineParts = line.components(separatedBy: .whitespaces).filter { !$0.isEmpty } if lineParts.count >= 3 { return lineParts[2...].joined(separator: " ") } } } return nil } // 使用示例 if let vendor = getDeviceVendor(from: "00:1A:2B:3C:4D:5E") { print("设备厂商:\(vendor)") }
补充说明
部分设备的Bonjour TXT记录中会包含vendor字段,可以优先尝试读取该字段,但OUI解析的方式兼容性更强,适用于所有网络设备。
三、关于_device-info._tcp在Ventura的可用性确认
该服务在Ventura下完全正常工作,你的代码未收到TXT消息的核心原因:
- 服务名称不匹配:硬编码的设备名称(如
Mac-Mini.local.)可能与设备实际发布的Bonjour名称不符(比如设备名称包含空格、特殊字符),必须通过NetServiceBrowser动态发现服务 - 未主动解析:直接调用
startMonitoring()不会触发服务解析,需要调用resolve(withTimeout:)主动获取服务的地址和TXT数据 - 权限缺失:未在
Info.plist中配置局域网访问权限,被系统拦截了服务请求
内容的提问来源于stack exchange,提问作者inexcitus
相关产品推荐
相关产品推荐

