I'd like to use Files.app to copy a folder (e.g. from Dropbox or iCloud), then switch to my App and read the contents of this folder for further processing. I can't find a way though to get the actual data from UIPasteboard. Calling loadObject on the NSItemProvider gives me an NSData archive which I can unarchive and then get a (private) FPItem, which implements <NSFileProviderItem>, but what now? How can I actually request downloading the actual folder this item points to?
I've used one of my precious Technical Support Incidents (TSI) to have an Apple engineer give a statement.
The outcome is that at this point of time, copy'n'paste of a folder in Files.app to your own app is not supported. If you want to import a folder, use a UIDocumentPickerViewController.
As I understand it, you would like to download a folder from Dropbox. You may want to consider using the Dropbox API with a URLSession.shared.datatask(...) using a REST request. If you don't want to deal with implementation details, you could use a library like SwiftyDropbox. There isn't really any need to use UIPasteboard because your end goal is downloading a folder to your app. If you would like to save said folder to the Files app, you can do so after you download/process the folder.
Here are some useful links:
Swifty Dropbox Overview
Swifty Dropbox Download Example
Swifty Dropbox API Docs
Dropbox API HTTP (RESTful Requests)
In link 2, the snippet of code below gets the directory to save the file in. One way you could get a whole folder is to (1) create a new folder in the Documents directory like this and (2) iterate through every item in the Dropbox folder and add that to the newly created folder.
let fileManager = FileManager.default
let directoryURL = fileManager.urls(for: .documentDirectory, in: .userDomainMask)[0]
let destURL = directoryURL.appendingPathComponent("myTestFile")
To implement (1), you would need to get all the files in a folder, which you can do with this /list_folder API endpoint. Then, to implement (2), you would iterate through all the files given, downloading them like in link 2.
Let me know if my answer helped, or if you need any further clarification. Thanks a bunch! :)
Related
I need some sort of file sharing functionality between two independent apps (cannot use AppGroup or something like that).
App1 should send to App2 n documents (n could be hundreds), App2 should elaborate these documents and send back to App1 the elaborated documents. I would like minimal user interaction (so I wouldn't use the UIActivityViewController or similar solutions)
By now I'm using custom url to allow the applications to call themselves, and the general UIPasteboard to share the documents. But since I have no control on the number or the size of the documents, I'm worried that this solution wouldn't be reliable
So I'm taking a look at the sharing features introduced in iOS 11, and I can see that using
UISupportsDocumentBrowser = TRUE
into App1's plist, I can share all the documents directory with Files app or with any document based app.
But I cannot understand if I can get the files from App1's documents folder with some sort of API, without using UIDocumentBrowserViewController.
Something like:
App1 set UISupportsDocumentBrowser,LSSupportsOpeningDocumentsInPlace,UIFileSharingEnabled = true and share its document folder
App1 call App2's custom url with a list of url of files that are inside App1's document folder
App2 launches and get the files reading from these urls (that are accessible because App1 share its document folder)
Does Anyone know if it's possible and there is an API to do this?
I have already tried to set UISupportsDocumentBrowser,LSSupportsOpeningDocumentsInPlace,UIFileSharingEnabled = TRUE in App1 and simply tried, from App2, to read a file url from inside App1's documents folder with Data(contentsOf: url), but this doesn't work (no read permissions)
Thanks to all!
We plan to store the following user files
SQLite file
Image files
Audio files
We also provide an option for users, to upload and download the above files, to a 3rd party cloud storage.
I was wondering, should we use
FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
or
FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask)
for the above file storage purpose?
Historically we used the “Documents” folder, but nowadays the “Application Support” directory is the best place for files like this.
The File System Programming Guide says
Put user data in Documents/. User data generally includes any files you might want to expose to the user—anything you might want the user to create, import, delete or edit. For a drawing app, user data includes any graphic files the user might create. For a text editor, it includes the text files. Video and audio apps may even include files that the user has downloaded to watch or listen to later.
Put app-created support files in the Library/Application support/ directory. In general, this directory includes files that the app uses to run but that should remain hidden from the user. This directory can also include data files, configuration files, templates and modified versions of resources loaded from the app bundle.
Remember that files in Documents/ and Application Support/ are backed up by default. You can exclude files from the backup by calling -[NSURL setResourceValue:forKey:error:] using the NSURLIsExcludedFromBackupKey key. Any file that can be re-created or downloaded must be excluded from the backup. This is particularly important for large media files. If your application downloads video or audio files, make sure they are not included in the backup.
Put temporary data in the tmp/ directory. Temporary data comprises any data that you do not need to persist for an extended period of time. Remember to delete those files when you are done with them so that they do not continue to consume space on the user’s device. The system will periodically purge these files when your app is not running; therefore, you cannot rely on these files persisting after your app terminates.
Put data cache files in the Library/Caches/ directory. Cache data can be used for any data that needs to persist longer than temporary data, but not as long as a support file. Generally speaking, the application does not require cache data to operate properly, but it can use cache data to improve performance. Examples of cache data include (but are not limited to) database cache files and transient, downloadable content. Note that the system may delete the Caches/ directory to free up disk space, so your app must be able to re-create or download these files as needed.
Also see the iOS Storage Best Practices video.
If using the .applicationSupportDirectory, I’d suggest you use url(for:in:appropriateFor:create:) with create set to true:
let folderURL = try! FileManager.default
.url(for: .applicationSupportDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
It doesn't make much difference which you choose. The chief difference is in case you want to use a file browser or the Files app; they can look in your documents directory but not in your application support directory.
Also if you pick one and release the app and later change your mind, it's easy to migrate and change where the app stores its information.
My iOS app is writing to local files to:
/var/mobile/Containers/Data/Application/A.../Library/a.txt
When my app updates, it gets a new application container ID and folder:
/var/mobile/Containers/Data/Application/B...
What happens to all the files I wrote to container ID A?
Is there an "update hook" that will allow me to copy all the "A" container files to path "B"?
Can the new version of the app (B) read the old versions files (A)?
Is there any documentation around what happens to the filesystem during updates?
Is it possible to recover files from container A after B has been installed?
When you update an app, by changing its version number in the .plist file, iOS creates a new directory for that app with a different hexadecimal name and it copies all the files to the new directories. Now if you are using the absolute paths to get the details of files from the directories then those paths would be incorrect and you won't get the file details.
I just tried this in simulator. I created a function as below which will return the document directory path url
func getDocumentsDirectory() -> URL {
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
let documentsDirectory = paths[0]
return documentsDirectory
}
I called this function from didFinishLaunchingWithOptions in app delegate when version number was 1.0 and it returned the below path :
file:///Users/BhargavRathod/Library/Developer/CoreSimulator/Devices/3082611F-BCCA-4D17-B390-E0EF4CA454DA/data/Containers/Data/Application/72759097-38F3-4292-825E-1D2343219973/Documents/
When I updated the version number to 1.1 it returned me the new path as :
file:///Users/BhargavRathod/Library/Developer/CoreSimulator/Devices/3082611F-BCCA-4D17-B390-E0EF4CA454DA/data/Containers/Data/Application/72DC31E9-C32F-42CC-8449-F1946ADB1018/Documents/
So if you are using a absolute path to access any file from document directory then it is not good practice. You can just save the file name(or relative path after the document directory) and whenever the access to that file name is required then get the file name and append it after the document directory path and access the file.
I hope this will be of some help to you.
My iOS app is writing to local files to: /var/mobile/Containers/Data/Application/A.../Library/a.txt
Okay, stop right there. This is wrong.
Your app has its own sandbox. This sandbox persists forever, thru updates, as long as your app keeps its Bundle ID, and as long as the user does not delete the app.
You thus have no business knowing or thinking about the full absolute path to where your file is. All you know, and all you need to know, is that it is in your app’s sandbox in the Library directory. You can, at any time, obtain the URL of the Library directory by means of its search path:
https://developer.apple.com/documentation/foundation/filemanager/searchpathdirectory/librarydirectory
And that is where the file will always be. As long as you ask the FileManager for your Library directory and for the a.txt file within it, you will find the same file, regardless of any updates, as long as the user doesn’t actually delete your app (because that deletes the sandbox).
Can explain what happens to the files
Nothing. They stay where they are within the sandbox. The absolute URL of the sandbox may change, but your files are unaffected.
how to keep the files written by the previous version of the app
They are kept automatically. You don’t have to do anything.
(Having said all that, keep in mind that if you submit an app with a different bundle id, that is not a new version of your app. It is a totally different app. In that case you would have a very different problem to solve. This would be no different from any other problem of communicating files from one app to another. You’d need to put the files in a common location, make them available thru the Document Browser, make them exportable by the user, or whatever.)
I have a Rails application which is suppose to upload images from a Dropbox URL pointed to a folder. The folder contains the images. Application is suppose to upload all images present in folder.
The URL is somewhat like this
https://www.dropbox.com/sh/17fsm6bsnac1g4q/AADJ7B2L0OIrkSrc7YcG-OO9a?dl=0
I can see the images but how can I get the list of all images URL. I have tried parsing the URL by appending dl=1 which downloads the images.
URI.parse('https://www.dropbox.com/sh/17fsm6bsnac1g4q/AADJ7B2L0OIrkSrc7YcG-OO9a?dl=1).
How can I get the URL of all images. If I can not get URL of images then how can i download all images and them upload them.
If you are okay with just downloading everything, you can make a GET request to the dl=1 version of the link you have. This URL parameter is documented here. This will give you a zipped version of the folder which you can then unzip and use as necessary.
Dropbox doesn't offer a way to get links for each of the files in the linked folder, but you can use the Dropbox API to list the files and then download them individually. You can use the /2/files/list_folder endpoint and pass the shared link in as the shared_link parameter. That will give you a list of the items in the folder.
You can then use /2/sharing/get_shared_link_file to download any desired file(s), by passing in the shared link as the url parameter, and the relative path for the file as the path parameter.
I'm using NSURLSessionDownloadTask to download some .mov files from a web and storing them in my app.
Now what I'd like to achieve is to
download ALL files of certain type (in this case .mov) available on the page, without having to specify every file URL
download files ONLY if they are not already stored in my app.
Is there any way to achieve this?
You would have to scrape that html page to get all the urls (.mov) you are looking for. Either you can use NSXMLParser if you want to write your own or you can google some library.
When you download a file, persist some metadata (eg. name or some unique identifier) either in SQLite or CoreData, so that you can check if the file has already been downloaded.