I know you can get the current machine's icon from cocoa using the following code:
NSImage *machineIcon = [NSImage imageNamed:NSImageNameComputer];
But is it possible to get the icon when given just a model number? Such as MacBookPro11,3
?
The reason I need this is because I'm using MultiPeer Connectivity
to browse devices on the network that I'd like to connect to. But I want to display the icons from those devices in a customized browser view.
I know that OS X has pretty much every icon for all the devices in the following folder:
/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/
but I want to know how to get access to them from within my app:
I thought about using the discoveryInfo
from MCNearbyServiceAdvertiser
to transmit an icon of the device advertising, but you can't transmit that much data using discoveryInfo
. It's designed only for small amounts of text. So I've decided to just transmit the machine's model number instead. I'm hoping to resolve the machine's model number to an icon on the other side. Kind of like how AirDrop
does it.
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
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With