6

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.

4

3 回答 3

5
  1. Mac App Store 安全

手动将模型标识符映射到图标名称,然后使用例如

[[NSWorkspace sharedWorkspace] iconForFileType:@"com.apple.macbookair"];

或者

 [NSImage imageNamed:NSImageNameComputer]

如果您需要比 imageNamed 提供的分辨率更高的分辨率,请使用

  OSType code = UTGetOSTypeFromString((CFStringRef)CFSTR("root"));
  NSImage *computer = [[NSWorkspace sharedWorkspace] iconForFileType:NSFileTypeForHFSTypeCode(code)];

其中“root”字符串来自 IconsCore.h 头文件 (kComputer)。

复制此 plist 以获取标识符(不要从应用沙箱访问它)

/System/Library/PrivateFrameworks/ServerInformation.framework/Versions/A/Resources/English.lproj/SIMachineAttributes.plist

  1. Mac App Store 不安全

将私有框架 SPSupport.Framework 与您的二进制添加框架搜索路径变量链接

$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks

将以下接口添加到您的项目中

#import <Cocoa/Cocoa.h>

@interface SPDocument : NSDocument

- (NSImage *)modelIcon;
- (id)computerName;
- (id)serialNumber;
- (id)modelName;

@end

调用您的代码:

  SPDocument *document = [[SPDocument alloc] init];
  NSImage *icon = [document modelIcon];
  1. 最难的方式

用这个私有函数弄清楚 CoreFoundation 跳舞(这个代码是说明性的,找到正确的类型、参数数量并正确释放)

  output = _LSCreateDeviceTypeIdentifierWithModelCode((CFStringRef)@"MacBookPro6,2");
  NSImage *image = [[NSWorkspace sharedWorkspace] iconForFileType: output];

编辑: 我刚刚意识到您需要选项编号 1,3(给定型号的图标)。GL 与此作斗争。

添加了EDIT2 方法 3。更改顺序并添加到编号 1 下。

EDIT3 彩色版本的新 UTI 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"];

如何获取型号/标识符(sysctl hw.model 已替换为 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];

并解析模型标识符或您的属性列表序列化

于 2015-09-03T11:09:52.287 回答
1

可以在不使用私有框架的情况下以编程方式将模型标识符转换为图像。此代码至少适用于 OS X 10.4 及更高版本。

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

请注意,当前rdr://27883672macOS 10.12 beta 6 中存在一个会在UTTypeCopyDeclaration. 这是因为UTTypeConformsTo可能返回 aCFStringRefCFArrayRefof CFStringRef。代码片段假定只CFStringRef返回 a 。

适应沙盒

要将此代码与沙盒一起使用,请避免直接加载图标文件。而是获取UTTypeIdentifierfromutiDecl并将其传递给NSWorkspace's iconForFileType

于 2016-08-18T10:36:55.457 回答
1

这是 Swift 中的一个解决方案,但它使用私有 API,因此请记住它可能会受到无证更改和 App Store 拒绝的影响。

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
    }

}

如果您不知道型号:

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

如果您知道该型号或想使用其他型号:

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

于 2015-09-03T16:45:36.850 回答