Is there a way of getting a Mac's icon given its model number?

前端 未结 3 1423
心在旅途
心在旅途 2020-12-04 01:50

I know you can get the current machine\'s icon from cocoa using the following code:

NSImage *machineIcon = [NSImage imageNamed:NSImageNameComputer];
<         


        
相关标签:
3条回答
  • 2020-12-04 02:26

    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

    0 讨论(0)
  • 2020-12-04 02:34

    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.

    Adapt for Sandboxing

    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.

    0 讨论(0)
  • 2020-12-04 02:36
    1. Mac App Store safe

    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

    1. Mac App Store unsafe

    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];
    
    1. Hardest way

    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

    0 讨论(0)
提交回复
热议问题