1

Is it possible to make user able to choose a destination for the file that he wants to download, something like DocumentPicker which you can use when choosing a file to upload?
I want something like this: img1

Willeke
  • 14,578
  • 4
  • 19
  • 47
stackich
  • 3,607
  • 3
  • 17
  • 41

1 Answers1

1

Yes, for iOS 13 and later you can ask the user to select a directory via UIDocumentPickerViewController. You'll get back a security scoped url(s) for the directories selected by the user.

Details here: https://developer.apple.com/documentation/uikit/view_controllers/providing_access_to_directories

I've pasted the sample code from that page below, but you'll want to read the documentation carefully because security scoped URLs require careful handling :)

If you need iOS 12 or earlier the user can only select files so I'm unclear on a clean way to do this (but we're on iOS 14 and iOS 15 is about to come out so hopefully you don't have to support back past iOS 13).

Here's the sample code from the link above showing how this is done:

// Create a document picker for directories.
let documentPicker =
    UIDocumentPickerViewController(forOpeningContentTypes: [.folder])
documentPicker.delegate = self

// Set the initial directory.
documentPicker.directoryURL = startingDirectory

// Present the document picker.
present(documentPicker, animated: true, completion: nil)
Dad
  • 6,388
  • 2
  • 28
  • 34
  • So you show us how to select a file. But that's not really the question he or she is asking, right? – El Tomato Aug 26 '21 at 11:59
  • Yikes! I pasted in the wrong sample from that documentation page. Fixed. Thanks @ElTomato – Dad Aug 26 '21 at 12:01
  • The key is the line: ` UIDocumentPickerViewController(forOpeningContentTypes: [.folder])` where you specify a document type of `.folder`. – Dad Aug 26 '21 at 12:04
  • haha lol @Dad thanks, that makes sense. But how can I access the chosen directory and save the file there? You have a snipper for it? I am using try FileManager.default.copyItem(at: url, to: dir). Is it possible to replace this "dir" with the choose destination, maybe there is a delegate method for it? – stackich Aug 26 '21 at 12:11
  • That's why you need to read the documentation at the link I provided. It's a security scoped url for the directory so you have to use `startAccessingSecurityScopedResource()` and then use a file coordinator to do the work inside the directory, and then use `stopAccessingSecurityScopedResource()` when you're done. It's a bit of a pain but a consequence of sandboxing and creating a file outside the app's sandbox. – Dad Aug 26 '21 at 12:17
  • @stackich you could try just wrapping your call to FileManager.default.copyItem(…) and use the url for the destination but wrap that call in the `start…` / `stop` SecurityScopedResource() above. If that doesn't work then I guess you need to use an NSFileCoordinator and coordinate(writingItemAt:) with the appropriate WritingOptions (.forReplacing most likely). – Dad Aug 26 '21 at 12:29
  • @Dad thanks but all this stuff with security is totally confusing for me. I am using DocumentPicker normally without it to import files in the app. And that is also a reason I need to get more deeply into didPickDocumentsAt because I use it for importing, I need to know how to use it for exporting, too. – stackich Aug 26 '21 at 13:04
  • A security scoped url means that you have a right to use that resource but you have to assert that right by saying "I'm starting to use this security scoped url for which I have obtained permission" == `url.startSecurityScopedResource()` and then you have to indicate when you're done via `url.stopSEcurityScopeResource()`. In between you do your file operations. – Dad Aug 26 '21 at 13:09
  • The documentation is not terrible, but you have to go read the documentation for each of those routines carefully. You can figure it out! (our job isn't to write it for you, just to point you at what you need to learn to do it yourself - that's how you get better :) Give it a try and come back if it works or if you get stuck.). – Dad Aug 26 '21 at 13:10
  • @Dad I have made some progress, but after selecting a destination folder and clicking Done, it says that I don't have permission to write there. Is the reason the security stuff we were talking about? – stackich Aug 26 '21 at 14:19
  • Yah, you can't write there until you add the `dstURL.startSecurityScopedResource()` call etc. If even adding that still doesn't work then you're probably going to have to use the File Coordinator like I mentioned above. – Dad Aug 26 '21 at 14:21
  • 1
    @Dad I am very grateful to you! Putting the `copyItem()`method between `startAccessingSecurityScopedResource()` & `stopAccessingSecurityScopedResource()` has solved my problem, now I can save files everywhere! :) I just hope that Apple won't bother me with this stuff when reviewing my app. FileManager is a science for itself. – stackich Aug 26 '21 at 22:34
  • What is startingDirectory? – El Tomato Aug 27 '21 at 00:08
  • 1
    @stackich Most Excellent! See, I *knew* you could figure it out. :) Nice job! – Dad Aug 27 '21 at 00:27
  • @ElTomato Not sure what stackich did, but normally you'd download the file to a temporary directory within your sandbox and then use the url of that as the startingDirectory for the move to the security scoped location the user chose. – Dad Aug 27 '21 at 15:51