Hi,
I am trying to use UIDocumentPickerViewController
to select a folder in a 3rd party file provider as a "default save location". The goal would be to have that folder be the automatic location to save to whenever the app needs to write a file out to disk, instead of the app's Documents directory.
When I present the UIDocumentPickerViewController for selecting folders, however, every 3rd party file provider is grayed out. Only "On this Device" and "iCloud Drive" are available.
let controller = UIDocumentPickerViewController(documentTypes: [kUTTypeFolder as String], in: .open)
controller.delegate = self
controller.allowsMultipleSelection = false
present(controller, animated: true, completion: nil)
The documentation states:
"With iOS 13, users can select a directory from any of the available file providers using a UIDocumentPickerViewController."
It seems strange that this is specifically called out in the docs, but it doesn't work at all. One hypothesis that I have is that there is some confusion in the system between kUTTypeFolder
and kUTTypeDirectory
which is causing this issue. But it's weird that this would be an issue from iOS 13 through iOS 15.
As a workaround, I also tried moving/copying a temporary directory with UIDocumentPickerViewController
to the 3rd party provider, and using the resulting security-scoped URL to create new files. However, it seems that it doesn't grant proper permissions because whenever I try to create files in that folder, it throws an error claiming the file doesn't exist (duh, that's what I'm trying to do.)
let temporary = try! TemporaryFile(creatingTempDirectoryForFilename: "placeholder")
FileManager.default.createFile(atPath: temporary.fileURL.path, contents: nil, attributes: nil)
let controller = UIDocumentPickerViewController(documentTypes: [kUTTypeFolder as String], in: .open)
controller.delegate = self
controller.allowsMultipleSelection = false
present(controller, animated: true, completion: nil)
func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
let folderURL = urls.first!
let randomNumber = String(format: "%X", arc4random())
guard folderURL.startAccessingSecurityScopedResource() else {
Swift.debugPrint("Cannot access security-scoped URL: \(folderURL)")
return
}
defer { folderURL.stopAccessingSecurityScopedResource() }
let fileURL = folderURL.appendingPathComponent(randomNumber).appendingPathExtension("txt")
var error: NSError?
NSFileCoordinator().coordinate(writingItemAt: fileURL, options: .forReplacing, error: &error) { fileURL in
let data = Data(randomNumber.utf8)
do {
try data.write(to: fileURL, options: [])
} catch {
print("error writing file:")
print(error)
}
}
}
error writing file:
Error Domain=NSCocoaErrorDomain Code=4 "The file “3A7F4A2.txt” doesn’t exist." UserInfo={NSFilePath=/private/var/mobile/Containers/Shared/AppGroup/D9D4024B-AD43-4B57-920B-D8E2B5ED7645/File Provider Storage/non-file/d_LOCAL-0A6C7195-23D8-43AE-9CBC-B84F063E2B44/3A7F4A2.txt, NSUnderlyingError=0x2817ea100 {Error Domain=NSPOSIXErrorDomain Code=2 "No such file or directory"}}
Does anyone have an idea for a workaround for this issue? Are there any known 3rd party file providers which are known to work? Is there any reason this would be disallowed? Finally, does anyone have an idea how I could implement the intended functionality in a way that I haven't thought of, yet?