Document Renaming with UIDocumentBrowserViewController - ios

I am using the "new way" of storing documents (iOS 11+) using UIDocumentBrowserViewController. No need for iCloud API, Entitlements etc. -- just works (under control of the separate Document Browser process).
However, I haven't figured out how to rename (i.e. move) a document programmatically this way, at least within iCloud. The standard "url.setResourceValues()" does work just fine on the local filesystem, but renders in 513/not permitted in iCloud. Also all the former ways of doing it (using full set of iCloud capabilities & entitlements, using complex FileCoordinator orchestration etc.) don't work either when the created document actually is controlled through the document browser.
I couldn't find any reasonable documentation or example on how to use the UIDocumentBrowser to also move a document under it's (and somewhat my) control. There is the UIDocumentBrowserImportModeMove mode that might do what I need, however I have no clue how to programmatically initiate that on a given UIDocument.
Has anyone already made experiences to do it this way?
Thanks, habitoti

There is no API to move a document that was returned to you by the document browser after the user picked it. You should file a bug with Apple to get one.
If this is inside your iCloud container, you can use the iCloud entitlements and -[NSFileManager URLForUbiquityContainerIdentifier:] to get sandbox access to your container and do whatever you want inside with NSFileManager; but that won't work in iCloud outside of your container or in other file providers (Dropbox...).

Related

UIDocumentPickerViewController Limitations, Multiple Files selection at once

In order to be able to access iCloud Drive from the application,
I think that we want to use UIDocumentPickerViewController from the application.
but i found following problems when i use UIDocumentPickerViewController.
Cannot upload multiple files at once.
Cannot Download multiple files at once.
When pushViewController from navigationController then display
become strange.
I want to avoid above problems, So is there any another way to get files information from iCloudDrive without using UIDocumentPickerViewController?
like Send some request or query.
I have searched lot and didn't find any query or request to get Files ,Upload files and download files from iCloudDrive.
if you have any idea about this please tell me.
Thanks,
I don't think there's any straightforward alternative, but you could think of...
...using iCloud directly (not iCloud Drive), but then users will only have access to their files from your application
...using Google Drive's sharing extension which supports uploading multiple files at once (the Dropbox SDK probably supports that, too, but their sharing extension doesn't)
...zipping all files before uploading them
...changing the file format so that it's a bundle of multiple files, if you are in control of the file format
...file a radar/feature request, and possibly wait forever ;)
Not sure if that helps, but I don't think you have much of a choice here.

hidden files with .icloud extension in ubiquity container

I am building app which syncs documents over the iCloud.
When I create document (lets say its name is myfile1.doc) in one device and expect to appear in another one I get nothing - it looks like it doesn't sync. To my surprise when I read the content of Documents folder in ubiquity container I can see the representation of the file is added as a hidden file with .icloud extension (in this case .myfile1.doc.icloud).
I tried to find more about this .icloud files but so far no results.
Anyone know what are they representing? Is it the metadata item that indicates that file was added to iCloud and I should manually download it?
I think hidden files are handled by metadataQuery to indicate that the new file was added to iCloud and is waiting to be sync'ed. NSMetadataQuery recognizes them as representation of new files not yet downloaded to ubiquity container.
These files are not documented and you should ignore them. If you want to know what's in them, open one in a hex editor and have a look. Your code should not check for them or access them in any way.

Document provider inconsistency

I am using the new document provider functionality to try to export files to third party cloud services:
UIDocumentMenuViewController* activity = [[UIDocumentMenuViewController alloc] initWithURL:writer.file
inMode:UIDocumentPickerModeExportToService];
When I run this, I see iCloud, Google Drive and Dropbox as an option (and they appear to work). What I don't see, even though I have the app installed, is Box.
What's more odd is that when I use UIDocumentPickerModeOpen, Box does appear, along with iCloud, but Dropbox and Google Drive are missing. I can't open the file from either provider, though; it won't let me select my custom document type. In another app where I just export a CSV file is seems to work without issue to all providers.
The file uses a custom file type, which I'm guessing is part of the problem. There are other questions here about that and I believe I've correctly followed the instructions.
Did I miss a step when adding a the custom file type? Are there other options when creating the document menu? Are there bugs in the document providers? (I note that it works in all cases with iCloud Drive.)
At this moment only iCloud Drive supports all four modes: import, export, open and move. Dropbox and Google Drive don't support open. Box does support open. I don't think there is much we developers can do except waiting for all the cloud providers to support all modes.
I am also using a custom UTI, and this setting is working for me. I can select a .qvlibrary file from iCloud Drive, and open it with a security-scoped URL. Remember to call -[NSURL startAccessingSecurityScopedResource] before accessing the files or directories.

How to determine if the local file is newer when moving local files to iCloud?

When the user enables iCloud in my app, I need to move all local files to iCloud. Here, I use setUbiquitous:itemAtURL:destinationURL:error: to move each file. The problem is, if (for any local file) the same file URL already exists on iCloud, this method fails.
My question is, how can I determine which file is newer (local vs iCloud) so that I can either overwrite the iCloud version or discard the local version for each file? Or, could I somehow force iOS to perform the upload and set the file state into conflict on iCloud so that my conflict resolution methods would take over and handle this?
FWIW, from Apple's dox they suggest an all-or-nothing iCloud approach - i.e., ask the user at one point whether or not iCloud should be enabled or not and then don't change.
That said, for your situation I'd suggest the following steps after the user enables iCloud:
1) Run an NSMetaDataQuery with ubiquitous scope to get the list of files already in the cloud for this app. (Note that the query must be run on the main thread or you get nothing back).
2) If you have a file of the same name, you can use the last modified date key (NSMetadataItemFSContentChangeDateKey) in the NSMetaData to figure out which one you should use (or whatever approach you want to use for resolving the conflict)
3) If the file is not already in the cloud, then use the setUbiquitous method to put it there.

How do I properly manage iCloud files via NSFileManager?

I am attempting to add iCloud synching to my iOS/Mac app by using the iCloud methods on NSFileManager (no documents or file coordinators). The app needs to synch audio files across the various instances; create, delete and metadata changes. It isn't a collaboration style app, so I am not very worried about conflicts, etc. I have something basic working, but have run into some basic questions that I can't seem to find definitive answers to.
When using iCloud, there are two local directories involved, the sandbox directory where the file originates and the ubiquity container directory. Once I enable a file for ubiquity, should I start interacting with the file in the ubiquity container directly or should I continue interacting with the sandbox file and pushing/pulling changes from the ubiquity counterpart? It feels like the latter is best so that I don't lose all the users files if they turn iCloud off (not sure what happens to files in ubiquity container in that case).
If I maintain two files, is there a preferred way to push/pull incremental changes to/from the ubiquity container? As I understand it, if a user changes a file on a given device, all other devices get the incremental changes in their local ubiquity copy (if downloaded). Should I just be copying the file in it's entirety over to my local sandbox directory every time the ubiquity file changes and vice versa?
Constantly copying files to the ubiquity container as they are modified doesn't seem like a good strategy to me and might even result in iCloud thinking more of the file has changed than really has. You can interact with files in the ubiquity container directly, working with them just as you would a file in your 'normal' document sandbox. This is the model prescribed in all of the iCloud documentation, sparse as it may be.
You're right that you need to be able to handle the situation where a user migrates away from iCloud. There are methods to move a file out of the ubiquity container and some of the newer iOS 6 API makes it easier to detect if the user has iCloud enabled, though this is still an area where we could use more API.

Resources