I'm trying to export my UIDocument
subclass with a UIDocumentPickerViewController
. The subclass writes data to a FileWrapper
and its UTI conforms to com.apple.package
.
But the presented document picker shows "Documents in iCloud Drive are not available because the iCloud Drive setting is disabled."
The document is successfully written to the cache, as I can see from the exported container package.
When I change the document subclass and custom UTI to conform to a single file (e.g. public.plain-text
), the document picker works fine and I can export the file. So the problem seems to be with the Document Type or Exported UTI.
Am I doing something wrong or is this a bug?
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)
}
}