有没有办法在给出型号的情况下获得Mac的图标?

时间:2015-09-03 07:57:16

标签: macos cocoa multipeer-connectivity airdrop

我知道你可以使用以下代码从cocoa获取当前机器的图标:

NSImage *machineIcon = [NSImage imageNamed:NSImageNameComputer];

但是只给出型号时是否可以获得图标?例如MacBookPro11,3

我需要这个的原因是因为我使用MultiPeer Connectivity来浏览我想要连接的网络设备。但我想在自定义的浏览器视图中显示这些设备中的图标。

我知道OS X几乎包含以下文件夹中所有设备的每个图标:

/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/

但我想知道如何从我的应用程序中访问它们:

我考虑过使用discoveryInfo中的MCNearbyServiceAdvertiser来传输设备广告的图标,但您无法使用discoveryInfo传输那么多数据。它仅针对少量文本而设计。所以我决定只传输机器的型号。我希望将机器的型号解析为另一侧的图标。有点像AirDrop的做法。

3 个答案:

答案 0 :(得分:5)

  1. Mac App Store安全
  2. 手动将模型标识符映射到图标名称,然后使用例如

    [[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不安全
    2. 将私有框架SPSupport.Framework链接到您的二进制文件 添加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. 最难的方式
      2. 使用此私有函数计算CoreFoundation舞蹈(此代码为插图,找到正确的类型,参数数量并正确释放)

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

        修改 我刚刚意识到你需要选项号1,3(给定型号的图标)。 GL与此斗争。

        <强> EDIT2 方法3补充说。更改了订单并在数字1下添加。

        <强> EDIT3 彩色版本的新UTI com.apple.macbook视网膜银 com.apple.device模型代码 MacBook8,1 @易彩= 225225223

        com.apple.macbook视网膜金 com.apple.device模型代码 MacBook8,1 @易彩= 235215191

        com.apple.macbook视网膜空间灰色 com.apple.device模型代码 MacBook8,1 @易彩= 155158159 MacBook8,1 @易彩= 157157160

        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];
        

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

答案 1 :(得分: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

答案 2 :(得分: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;
 }

请注意,macOS 10.12 beta 6中的错误rdr://27883672UTTypeCopyDeclaration内崩溃。这是因为UTTypeConformsTo可能会返回CFStringRefCFArrayRef CFStringRef。代码段假定只返回CFStringRef

适应沙盒

要将此代码与沙盒一起使用,请避免直接加载图标文件。而是从UTTypeIdentifier获取utiDecl并将其传递给NSWorkspace的{​​{1}}。