使用自定义文件包 UTI 导出 UIDocument

Export UIDocument with custom file package UTI

我正在尝试使用 UIDocumentPickerViewController 导出我的 UIDocument 子类。子类向一个FileWrapper写入数据,其UTI符合com.apple.package.

但是出现的文档选择器显示 "Documents in iCloud Drive are not available because the iCloud Drive setting is disabled."

从导出的容器包中可以看出,文档写入缓存成功

当我更改文档子类和自定义 UTI 以符合单个文件(例如 public.plain-text)时,文档选择器工作正常并且我可以导出文件。所以问题似乎出在文档类型或导出的 UTI 上。

我是不是做错了什么或者这是一个错误?


Info.plist

<key>CFBundleDocumentTypes</key>
<array>
    <dict>
        <key>CFBundleTypeIconFiles</key>
        <array/>
        <key>CFBundleTypeName</key>
        <string>Custom Doc</string>
        <key>LSHandlerRank</key>
        <string>Owner</string>
        <key>LSItemContentTypes</key>
        <array>
            <string>com.zxzxlch.documentsandbox.customdoc</string>
        </array>
        <key>LSTypeIsPackage</key>
        <true/>
    </dict>
</array>

...

<key>UTExportedTypeDeclarations</key>
<array>
    <dict>
        <key>UTTypeConformsTo</key>
        <array>
            <string>com.apple.package</string>
        </array>
        <key>UTTypeDescription</key>
        <string>Custom Doc File</string>
        <key>UTTypeIdentifier</key>
        <string>com.zxzxlch.documentsandbox.customdoc</string>
        <key>UTTypeTagSpecification</key>
        <dict>
            <key>public.filename-extension</key>
            <array>
                <string>zzz</string>
            </array>
        </dict>
    </dict>
</array>

CustomDocument.swift

private let textFilename = "contents.txt"

class CustomDocument: UIDocument {
    var content = "Test"

    override func load(fromContents contents: Any, ofType typeName: String?) throws {
        guard let topFileWrapper = contents as? FileWrapper,
            let textData = topFileWrapper.fileWrappers?[textFilename]?.regularFileContents else {
                return
        }
        content = String(data: textData, encoding: .utf8)!
    }

    override func contents(forType typeName: String) throws -> Any {
        let textFileWrapper = FileWrapper(regularFileWithContents: content.data(using: .utf8)!)
        textFileWrapper.preferredFilename = textFilename

        return FileWrapper(directoryWithFileWrappers: [textFilename: textFileWrapper])
    }

}

ViewController.swift

func exportDocument() {
    // Write to cache
    let cachesDir = FileManager.default.urls(for: FileManager.SearchPathDirectory.cachesDirectory, in: .allDomainsMask).first!
    let dataDir = cachesDir.appendingPathComponent("export", isDirectory: true)
    try! FileManager.default.createDirectory(at: dataDir, withIntermediateDirectories: true, attributes: nil)

    let fileURL = dataDir.appendingPathComponent("cookie").appendingPathExtension("zzz")

    let archive = CustomDocument(fileURL: fileURL)
    archive.content = "Cookie cat"

    archive.save(to: archive.fileURL, for: .forCreating) { success in
        guard success else {
            let alertController = UIAlertController.notice(title: "Cannot export data", message: nil)
            self.present(alertController, animated: true, completion: nil)
            return
        }

        let documentPicker = UIDocumentPickerViewController(url: archive.fileURL, in: .exportToService)
        documentPicker.delegate = self
        self.present(documentPicker, animated: true, completion: nil)
    }

}

这解决了我的问题:使 UTI 也符合 public.composite-content,即

<key>UTTypeConformsTo</key>
<array>
    <string>com.apple.package</string>
    <string>public.composite-content</string>
</array>

虽然我不确定为什么。