I know you can get the current machine\'s icon from cocoa using the following code:
NSImage *machineIcon = [NSImage imageNamed:NSImageNameComputer];
<
Here's a solution in Swift, but it uses a private API so remember that it might be subject to undocumented change and App Store rejection.
struct MachineAttributes {
let privateFrameworksURL = "/System/Library/PrivateFrameworks/ServerInformation.framework/Versions/A/Resources/English.lproj/SIMachineAttributes.plist"
var model: String?
var attributes: [String:AnyObject]?
var iconPath: String?
init() {
self.model = getModel()
self.attributes = getAttributes()
self.iconPath = getIconPath()
}
init(model: String) {
self.model = model
self.attributes = getAttributes()
self.iconPath = getIconPath()
}
private func getModel() -> String? {
let service: io_service_t = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("IOPlatformExpertDevice"))
let cfstr = "model" as CFString
if let model = IORegistryEntryCreateCFProperty(service, cfstr, kCFAllocatorDefault, 0).takeUnretainedValue() as? NSData {
if let nsstr = NSString(CString: UnsafePointer<Int8>(model.bytes), encoding: NSUTF8StringEncoding) {
return String(nsstr)
}
}
return nil
}
private func getAttributes() -> [String:AnyObject]? {
if let dict = NSDictionary(contentsOfFile: privateFrameworksURL) as? [String:AnyObject],
let id = model,
let result = dict[id] as? [String:AnyObject] {
return result
}
return nil
}
private func getIconPath() -> String? {
if let attr = self.attributes, let path = attr["hardwareImageName"] as? String {
return path
}
return nil
}
}
If you don't know the model:
let myMachine = MachineAttributes()
if let model = myMachine.model {
print(model)
}
if let iconPath = myMachine.iconPath {
print(iconPath)
}
MacBookPro9,2
/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/com.apple.macbookpro-15-unibody.icns
If you know the model or want to use another one:
let myNamedMachine = MachineAttributes(model: "iMac14,2")
if let iconPath = myNamedMachine.iconPath {
print(iconPath)
}
/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/com.apple.imac-unibody-27-no-optical.icns
It is possible to programmatically convert model identifiers to images without using private frameworks. This code works on at least OS X 10.4 and later.
+ (NSImage*)imageForMachineModel:(NSString*)machineModel
{
NSImage* image = nil;
NSString* uti = NULL;
if ((machineModel != nil) &&
([machineModel length] > 0))
{
NSString* fixedModel = [NSString stringWithUTF8String:machineModel.UTF8String];
uti = (__bridge_transfer NSString*) UTTypeCreatePreferredIdentifierForTag(CFSTR("com.apple.device-model-code"),(__bridge CFStringRef)fixedModel,NULL);
}
else
{
// Default to a generic Mac image for null
uti = (__bridge_transfer NSString*) CFStringCreateCopy(kCFAllocatorDefault,CFSTR("com.apple.mac"));
}
if (uti != NULL)
{
CFDictionaryRef utiDecl = UTTypeCopyDeclaration((__bridge CFStringRef)(uti));
if (utiDecl != NULL)
{
CFStringRef iconFileName = CFDictionaryGetValue(utiDecl,CFSTR("UTTypeIconFile"));
if (iconFileName == NULL)
{
while((iconFileName == NULL) &&
(utiDecl != NULL) &&
(uti != NULL))
{
// BUG: macOS 10.12 may return string or array of strings; unchecked in this implementation!
uti = NULL;
uti = CFDictionaryGetValue(utiDecl,CFSTR("UTTypeConformsTo"));
if (uti != NULL)
{
CFRelease(utiDecl);
utiDecl = NULL;
utiDecl = UTTypeCopyDeclaration((__bridge CFStringRef)(uti));
if (utiDecl != NULL)
{
iconFileName = CFDictionaryGetValue(utiDecl,CFSTR("UTTypeIconFile"));
}
}
}
}
if (iconFileName != NULL)
{
CFURLRef bundleURL = UTTypeCopyDeclaringBundleURL((__bridge CFStringRef)(uti));
if (bundleURL != NULL)
{
NSBundle* bundle = [NSBundle bundleWithPath:[(__bridge NSURL*)bundleURL path]];
if (bundle != nil)
{
NSString* iconPath = [bundle pathForResource:(__bridge NSString*)iconFileName ofType:nil];
if (iconPath != nil)
{
image = [[NSImage alloc] initWithContentsOfFile:iconPath];
}
}
CFRelease(bundleURL);
}
}
if (utiDecl != NULL)
{
CFRelease(utiDecl);
}
}
}
if (image == nil)
{
// Do something sensible if no image found
}
return image;
}
Be aware there is currently a bug rdr://27883672
in macOS 10.12 beta 6 that crashes within UTTypeCopyDeclaration
. This is because UTTypeConformsTo
may return either a CFStringRef
or CFArrayRef
of CFStringRef
. The code snippet assumes only a CFStringRef
will ever be returned.
To use this code with sandboxing, avoid directly loading the icon file. Instead get the UTTypeIdentifier
from utiDecl
and pass that to NSWorkspace
's iconForFileType
.
Manually map model identifier to icon name and then use e.g
[[NSWorkspace sharedWorkspace] iconForFileType:@"com.apple.macbookair"];
or
[NSImage imageNamed:NSImageNameComputer]
If you need higher resolution than imageNamed provides use
OSType code = UTGetOSTypeFromString((CFStringRef)CFSTR("root"));
NSImage *computer = [[NSWorkspace sharedWorkspace] iconForFileType:NSFileTypeForHFSTypeCode(code)];
where "root" string is from IconsCore.h header file (kComputer).
Copy this plist to get the identifiers (do not access it from app sandbox)
/System/Library/PrivateFrameworks/ServerInformation.framework/Versions/A/Resources/English.lproj/SIMachineAttributes.plist
Link Private Framework SPSupport.Framework with your binary Add FrameWork Search path variable
$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks
Add following interface into your project
#import <Cocoa/Cocoa.h>
@interface SPDocument : NSDocument
- (NSImage *)modelIcon;
- (id)computerName;
- (id)serialNumber;
- (id)modelName;
@end
Call in your code:
SPDocument *document = [[SPDocument alloc] init];
NSImage *icon = [document modelIcon];
Figure out CoreFoundation dance with this private function (this code is illustration, find correct types, number of params and release properly)
output = _LSCreateDeviceTypeIdentifierWithModelCode((CFStringRef)@"MacBookPro6,2"); NSImage *image = [[NSWorkspace sharedWorkspace] iconForFileType: output];
EDIT: I just realized that you need option number 1,3 (icon for given model). GL fighting this.
EDIT2 Method 3 added. Changed the order and added under number 1.
EDIT3 New UTIs for the colored version com.apple.macbook-retina-silver com.apple.device-model-code MacBook8,1@ECOLOR=225,225,223
com.apple.macbook-retina-gold com.apple.device-model-code MacBook8,1@ECOLOR=235,215,191
com.apple.macbook-retina-space-gray com.apple.device-model-code MacBook8,1@ECOLOR=155,158,159 MacBook8,1@ECOLOR=157,157,160
NSImage *image =[[NSWorkspace sharedWorkspace] iconForFileType:@"com.apple.macbook-retina-gold"];
How to get model number/identifier (sysctl hw.model was replaced by system_profiler)?
NSPipe *outputPipe = [NSPipe pipe];
NSTask *task = [[NSTask alloc] init];
[task setLaunchPath:@"/usr/sbin/system_profiler"];
[task setArguments:@[@"SPHardwareDataType"]];
[task setStandardOutput:outputPipe];
[task launch];
[task waitUntilExit];
NSData *outputData = [[outputPipe fileHandleForReading] readDataToEndOfFile];
NSString *hardware = [[NSString alloc] initWithData:outputData encoding:NSUTF8StringEncoding];
And parse Model identifier or your propertylistserialization