每台 Mac 都有一个型号标识符,例如“Macmini5,1”。 (这些显示在系统信息应用程序中。)
如何以编程方式获取此模型标识符字符串?
使用 IOKit 的 Swift 4+
import IOKit
func getModelIdentifier() -> String? {
let service = IOServiceGetMatchingService(kIOMasterPortDefault,
IOServiceMatching("IOPlatformExpertDevice"))
var modelIdentifier: String?
if let modelData = IORegistryEntryCreateCFProperty(service, "model" as CFString, kCFAllocatorDefault, 0).takeRetainedValue() as? Data {
modelIdentifier = String(data: modelData, encoding: .utf8)?.trimmingCharacters(in: .controlCharacters)
}
IOObjectRelease(service)
return modelIdentifier
}
您可以使用
sysctl
#import <Foundation/Foundation.h>
#import <sys/sysctl.h>
NSString *ModelIdentifier()
{
NSString *result=@"Unknown Mac";
size_t len=0;
sysctlbyname("hw.model", NULL, &len, NULL, 0);
if (len) {
NSMutableData *data=[NSMutableData dataWithLength:len];
sysctlbyname("hw.model", [data mutableBytes], &len, NULL, 0);
result=[NSString stringWithUTF8String:[data bytes]];
}
return result;
}
您也可以使用
IOKit.framework
。我认为这是最好的选择。
这个简单的代码示例展示了如何从 I/O Kit 注册表读取模型标识符到
NSString
:
- (NSString *)modelIdentifier {
io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault,
IOServiceMatching("IOPlatformExpertDevice"));
CFStringRef model = IORegistryEntryCreateCFProperty(service,
CFSTR("model"),
kCFAllocatorDefault,
0);
NSString *modelIdentifier = [[NSString alloc] initWithData:(__bridge NSData *)model
encoding:NSUTF8StringEncoding];
CFRelease(model);
IOObjectRelease(service);
return modelIdentifier;
}
字符串 “IOPlatformExpertDevice” 和 “model” 用于从 I/O Kit 注册表读取模型标识符。当您想要从 I/O Kit 注册表查找信息时,
ioreg
命令行工具是您的朋友。此图显示了 ioreg
输出中的这些字符串:
我希望这有助于使用
IOKit.framework
。
Ryan H的答案是正确的,除了从
null-terminated string
到Swift String
的不正确转换,最后给出了带有\0
符号的结果,这是你可能意想不到的,执行完全匹配。这是更正后的版本:
static private func modelIdentifier() -> String? {
let service = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("IOPlatformExpertDevice"))
defer { IOObjectRelease(service) }
if let modelData = IORegistryEntryCreateCFProperty(service, "model" as CFString, kCFAllocatorDefault, 0).takeRetainedValue() as? Data {
return modelData.withUnsafeBytes { (cString: UnsafePointer<UInt8>) -> String in
return String(cString: cString)
}
}
return nil
}
您可以从 system_profiler 命令获得相同的输出。它有一个可供您使用的
-xml
选项。 NSTask
可以为您运行命令,您可以解析结果。
示例代码:
#import <Foundation/Foundation.h>
NSString *ModelIdentifier() {
NSPipe *pipe=[NSPipe pipe];
NSTask *task=[[NSTask alloc] init];
[task setLaunchPath:@"/usr/sbin/system_profiler"];
[task setArguments:@[@"-xml", @"SPHardwareDataType"]];
[task setStandardOutput:pipe];
[task launch];
NSData *outData=[[pipe fileHandleForReading] readDataToEndOfFile];
NSString *outString=[[NSString alloc] initWithData:outData encoding:NSUTF8StringEncoding];
return [outString propertyList][0][@"_items"][0][@"machine_model"];
}
CFStringRef model = IORegistryEntryCreateCFProperty(service,
CFSTR("model"),
kCFAllocatorDefault,
0); ? type is ok ?
我认为代码可能是这样的:
CFSDataRef model = IORegistryEntryCreateCFProperty(service,
CFSTR("model"),
kCFAllocatorDefault,
0);
对于也构建到 Mac Catalyst 的 iOS 16 应用程序,此处任何使用
kIOMasterPortDefault
的解决方案(例如 Ryan H 的)都会生成构建错误:
“kIOMasterPortDefault”在 Mac Catalyst 中不可用
尝试将
kIOMasterPortDefault
切换到 kIOMainPortDefault
也可能会出现构建错误,具体取决于您所针对的 Catalyst 版本 - 我发现尝试使用 #available
来解决这个问题也不起作用。
如果您遇到这种情况,请尝试以下操作,这是将 Parag Bafna 的答案重新表述为 Swift:
var modelIdentifier: String {
#if targetEnvironment(macCatalyst)
var size = 0
sysctlbyname("hw.model", nil, &size, nil, 0)
var modelIdentifier: [CChar] = Array(repeating: 0, count: size)
sysctlbyname("hw.model", &modelIdentifier, &size, nil, 0)
return String(cString: modelIdentifier)
#else
// Handle iOS
#endif
}
var deviceName: String {
var str = "Unknown Device"
var len = 0
sysctlbyname("hw.model", nil, &len, nil, 0)
if len > 0 {
var data = Data(count: len)
sysctlbyname("hw.model", &data, &len, nil, 0)
if let s = String(bytes: data, encoding: .utf8) {
str = s
}
}
return str
}