bmike
bmike

Reputation: 971

How does System Profiler retrieve the full Mac hardware identifier?

There are several terminal commands to retrieve the numerical / abbreviated Model Identifier for Mac hardware.

These dump a string with the hardware name and x,y versioning. Currently we have to maintain a table to convert these identifiers into the full english machine description.

Is there an API, or better a command line tool that can produce the more human friendly names that match Apple's documentation MacBook Pro 15-inch, Mid 2009 or MacBook Pro (13-inch, 2016, Four Thunderbolt 3 Ports) instead of the more abbreviated MacBookPro5,3 or MacBookPro13,2 Model Identifier?

MacBookPro5,3 MacBookPro13,2

To summarize, how does System Profiler get the full localized names of Macintosh hardware in a way I can generate to consume that information systematically via script or program?

Upvotes: 24

Views: 12396

Answers (4)

Oskar
Oskar

Reputation: 3702

No need for web requests to get this info.

The current model, as it appears in About This Mac, can be gathered from:

~/Library/Preferences/com.apple.SystemProfiler.plist

The plist contains names localized in the current users added languages:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>GTF1-sv-SE_SE</key>
    <string>MacBook Pro (15 tum, 2016)</string>
    <key>GTF1-en-SE_SE</key>
    <string>MacBook Pro (15-inch, 2016)</string>
</dict>
</plist>

Where the keys are simply the last 4 letters of the serial number (GTF1) followed by locale.

If you want to, you can even edit this plist to customise your About This Mac window, a common practice amongst Hackintosh users.

EDIT:

Full implementation in Swift 5:

public enum SystemInfo {

    public static var serialNumber: String? {
        let service = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("IOPlatformExpertDevice"))
        return IORegistryEntryCreateCFProperty(service, "IOPlatformSerialNumber" as CFString, kCFAllocatorDefault, 0).takeUnretainedValue() as? String
    }

    public static var modelName: String? {
        guard let serial = serialNumber,
            let plist = try? PropertyList.load(from: .init(fileURLWithPath: "\(NSHomeDirectory())/Library/Preferences/com.apple.SystemProfiler.plist")),
            let regionCode = Locale.current.regionCode,
            let names = plist["CPU Names"] as? [String: String],
            !names.isEmpty else {
                return nil
        }
        for language in Locale.preferredLanguages {
            let key = "\(serial.suffix(4))-\(language)_\(regionCode)"
            if let entry = names[key] {
                return entry
            }
        }
        return nil
    }

}

Where I'm also using this helper enum:

public enum PropertyList {

    public static func load(from url: URL) throws -> [String: Any]? {
        guard let plist = FileManager.default.contents(atPath: url.path) else { return nil }
        var format = PropertyListSerialization.PropertyListFormat.xml
        return try PropertyListSerialization.propertyList(from: plist, options: .mutableContainersAndLeaves, format: &format) as? [String: Any]
    }

    public static func save(_ plist: [String: Any], to url: URL) throws {
        let data = try PropertyListSerialization.data(fromPropertyList: plist, format: .xml, options: 0)
        try data.write(to: url, options: .atomic)
    }

}

Usage:

print(SystemInfo.modelName)

Returns (Swedish):

MacBook Pro (15 tum, 2016)

Upvotes: 7

JWWalker
JWWalker

Reputation: 22717

You could use system_profiler -xml SPHardwareDataType and look for the machine_name key.

EDIT: Granted, this doesn't answer the question in the title of how the System Profiler does it, but it provides a way to do it in your own code.

Upvotes: 5

Monobono
Monobono

Reputation: 780

Did check the network traffic. System Information is connecting to

http://support-sp.apple.com

A full query looks like:

http://support-sp.apple.com/sp/product?cc=DJWR&lang=de_DE

Where 'DJWR' are the last four characters of the serial number

More info here: http://blog.coriolis.ch/get-your-apple-device-model-name-in-a-readable-format/

Upvotes: 16

lowell
lowell

Reputation: 517

ServerKit.framework has a property list within its resources that can help you with model identifier <-> model name string translation:

/System/Library/PrivateFrameworks/ServerKit.framework/Versions/A/Resources/English.lproj/XSMachineAttributes.plist

Upvotes: 14

Related Questions