swift - NSDocumentController.openDocument 不允许选择自定义文件类型

标签 swift xcode cocoa nsdocument nsopenpanel

我怀疑这是一个挑剔的配置问题,我在 Info.plist 中的文档类型/UTI 声明出错,但尝试了几种方法但没有找到解决方案。

我有一个基于 NSDocument 的 Mac 应用程序,用 Swift、Xcode 11 编写。它读取和写入后缀为“mpxml”的自定义文档类型。

enter image description here

在大多数早期开发过程中,我没有该类型的自定义 UTI 标识符(标识符字段留空,项目默认),并且应用程序能够读取和写入这些文件。

最近我更改为拥有完全限定的文档类型标识符和编辑器,这似乎是让我的文档图标显示在 Finder 中所必需的。我更改了代码中引用文档类型的所有位置以使用此完全限定的 UTI。现在一切正常,除了打开的面板(由默认的 NSDocumentController openDocument 运行)不再识别我的文件类型 - 所有带有“mpxml”后缀的文件现在在打开的面板中呈灰色显示,包括任何新创建的文件(保存面板工作正常)编写文件)。

我尝试过的一些事情:

  • 向我的 NSDocument 子类添加一些额外的重写:fileNameExtension()、writableTypes 等。
  • 设置/省略 mime-type
  • 设置/省略 4 个字符的 OSType
  • 设置/省略引用网址
  • 从文档类型中删除 mpxml 扩展名(因此它仅在 UTI 中定义) - 不起作用
  • 还将类型声明为导入的 UTI(不需要,没有解决问题)
  • 正在审阅文档:Developing a Document-Based App , Declaring New Uniform Type Identifiers

值得注意:documentation on CFBundleTypeExtensions (相关文档类型 plist 键)表示,如果设置了 LSItemContentTypes,它将被忽略 - 情况就是如此,因为 LSItemContentTypes 是 UTI 标识符的键。但如果设置它破坏了文档类型后缀从属关系,我希望 UTI 导出从属关系重新连接它。

另外:打开最近的文档也被破坏,在尝试打开最近保存的文档时,报告的错误是应用程序“无法打开这种类型的文件”。

我不确定绕过 NSDocumentController 的解决方法在这里是否有效,因为我不想弄乱它在幕后设置的文档实例/窗口/文件关联。

要让自定义 UTI 和扩展在此应用程序中正常工作,缺少什么?


更新基于此处的请求,是与此错误相关的附加 Info.plist 数据(基本上与上面屏幕截图中的 XCode 文档类型信息一致)。我现在已经创建了一个最小的示例应用程序,它重现了我将用于 Apple 错误报告的错误。

在项目的原始形式中,没有声明自定义UTI,Info.plist文档类型声明是:

<key>CFBundleDocumentTypes</key>
<array>
    <dict>
        <key>CFBundleTypeExtensions</key>
        <array>
            <string>asdfg</string>
        </array>
        <key>CFBundleTypeIconFile</key>
        <string></string>
        <key>CFBundleTypeName</key>
        <string>example document</string>
        <key>CFBundleTypeOSTypes</key>
        <array>
            <string>CCdc</string>
        </array>
        <key>CFBundleTypeRole</key>
        <string>Editor</string>
        <key>LSTypeIsPackage</key>
        <integer>0</integer>
        <key>NSDocumentClass</key>
        <string>$(PRODUCT_MODULE_NAME).CCDocument</string>
    </dict>
</array>

本项目用于成功读写后缀为.asdfg的非空文档。

然后,我通过为此扩展创建自定义 UTI 来更新 Info.plist。此时Info.plist如下(文档类型和UTI仅有变化):

<key>CFBundleDocumentTypes</key>
<array>
    <dict>
        <key>CFBundleTypeExtensions</key>
        <array/>
        <key>CFBundleTypeIconFile</key>
        <string></string>
        <key>CFBundleTypeName</key>
        <string>ccutibug document</string>
        <key>CFBundleTypeRole</key>
        <string>Editor</string>
        <key>LSItemContentTypes</key>
        <array>
            <string>com.mathaesthetics.ccutibug</string>
        </array>
        <key>LSTypeIsPackage</key>
        <integer>0</integer>
        <key>NSDocumentClass</key>
        <string>$(PRODUCT_MODULE_NAME).CCDocument</string>
    </dict>
</array>
<key>UTExportedTypeDeclarations</key>
<array>
    <dict>
        <key>UTTypeDescription</key>
        <string>ccutibug document</string>
        <key>UTTypeIdentifier</key>
        <string>com.mathaesthetics.ccutibug</string>
        <key>UTTypeTagSpecification</key>
        <dict>
            <key>com.apple.ostype</key>
            <array>
                <string>CCdc</string>
            </array>
            <key>public.filename-extension</key>
            <array>
                <string>asdfg</string>
            </array>
        </dict>
    </dict>
</array>

对最小测试项目进行此更改后,会出现原始描述的相同症状 - 打开面板现在已禁用所有 .asdfg 文档,“打开最近”不再起作用,但我仍然可以创建和保存这些文档。 @catlan 建议的干净重建加上 lsregister 修复仍然无法纠正它。

我再次可以通过直接使用打开面板来确认,单独提供 UTI 并不能启用打开面板来支持扩展名,只有显式提供扩展名才能让我打开保存的文档,并且无法通过 NSDocumentController 的处理来做到这一点AFAIK 打开面板或最近打开的菜单。

最佳答案

您的UTExportedTypeDeclarations条目丢失 UTTypeConformsTo 。该 key 是必需的。请参阅Uniform Type Identifier Concepts - ConformanceDeclaring New Uniform Type Identifiers

Although a custom UTI can conform to any UTI, public.data or com.apple.package must be at the root of the conformance hierarchy for all custom UTIs that are file formats (such as documents);

另外:

You need to declare conformance only with your type’s immediate “superclass,” because the conformance hierarchy allows for inheritance between identifiers. That is, if you declare your identifier as conforming to the public.tiff identifier, it automatically conforms to identifiers higher up in the hierarchy, such as public.image and public.data.

System-Declared Uniform Type Identifiers

<key>UTExportedTypeDeclarations</key>
<array>
    <dict>
        <key>UTTypeConformsTo</key>
        <array>
            <string>public.data</string>
        </array>
        <key>UTTypeDescription</key>
        <string>ccutibug document</string>
        <key>UTTypeIdentifier</key>
        <string>com.mathaesthetics.ccutibug</string>
        <key>UTTypeTagSpecification</key>
        <dict>
            <key>public.filename-extension</key>
            <array>
                <string>asdfg</string>
            </array>
        </dict>
    </dict>
</array>

我还删除了 com.apple.ostype ,它在经典 Mac OS 中使用,新文件类型不需要。

并匹配public.filename-extensionCFBundleTypeExtensions :

<key>CFBundleDocumentTypes</key>
<array>
    <dict>
        <key>CFBundleTypeExtensions</key>
        <array>
            <string>asdfg</string>
        </array>
        <key>CFBundleTypeIconFile</key>
        <string></string>
        <key>CFBundleTypeName</key>
        <string>ccutibug document</string>
        <key>CFBundleTypeRole</key>
        <string>Editor</string>
        <key>LSItemContentTypes</key>
        <array>
            <string>com.mathaesthetics.ccutibug</string>
        </array>
        <key>LSTypeIsPackage</key>
        <false/>
        <key>NSDocumentClass</key>
        <string>$(PRODUCT_MODULE_NAME).CCDocument</string>
    </dict>
</array>

注意:我还更改了 <integer>0</integer><false/>使其更具可读性。

调试

在开发过程中,更改 UTI 可能会混淆 LaunchServices 数据库。您可以尝试通过运行来重置它:

/System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister -kill -r -domain local -domain system -domain user

注意:确保您的系统上没有任何旧的开发版本,例如 Xcode 构建文件夹或 Xcode 产品文件中的版本。这些可能会继续混淆 LaunchServices 数据库

-dump选项有助于查看当前的 UTI 声明:

/System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister -dump

关于swift - NSDocumentController.openDocument 不允许选择自定义文件类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62288573/

相关文章:

ios - 读取核心数据时出错 : ios swift

ios - 如何创建穿过一层进入另一层的窗口

objective-c - 当 Swift 桥接头导入导入 Hopscotch-Swift.h 本身的文件时,如何防止循环引用

cocoa - Mac上command+q的消息流程是怎样的

cocoa - 应用程序启动前进行版本检查 cocoa

ios - Swift 日期相当于 30 纳秒以下

ios - 禁用 iPhone X 约束

swift - 如何创建具有不同数据类型的数据结构?

ios - 如何摆脱 Xcode 中的 "Unknown type name ' __declspec'"错误

iphone - 从 UIPageViewController 卸载 viewController