在 macOS 上获取型号标识符字符串

问题描述 投票:0回答:8

每台 Mac 都有一个型号标识符,例如“Macmini5,1”。 (这些显示在系统信息应用程序中。)

enter image description here

如何以编程方式获取此模型标识符字符串?

macos cocoa core-foundation
8个回答
17
投票

使用 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
}

8
投票

您可以使用

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;
}

7
投票

您也可以使用

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


6
投票

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
}

2
投票

您可以从 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"];
}

1
投票
CFStringRef model = IORegistryEntryCreateCFProperty(service, 
                                                        CFSTR("model"), 
                                                        kCFAllocatorDefault, 
                                                        0);  ? type is ok ?

我认为代码可能是这样的:

CFSDataRef model = IORegistryEntryCreateCFProperty(service, 
                                                        CFSTR("model"), 
                                                        kCFAllocatorDefault, 
                                                        0);  

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
}

0
投票

Parag Bafna 优秀答案的 Swift 版本

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
    }
© www.soinside.com 2019 - 2024. All rights reserved.