Save iOS 8 Documents to Icloud Drive

Save iOS 8 Documents to iCloud Drive

Well, you've got me interested in this matter myself and as a result I've spent way to much time on this question, but now that I've got it working I hope it helps you as well!

File on my Mac

To see what actually happens in the background, you can have a look at ~/Library/Mobile Documents/, as this is the folder where the files eventually will show up. Another very cool utility is brctl, to monitor what happens on your mac after storing a file in the iCloud. Run brctl log --wait --shorten from a Terminal window to start the log.

First thing to do, after enabling the iCloud ability (with iCloud documents selected), is provide information for iCloud Drive Support (Enabling iCloud Drive Support). I also had to bump my bundle version before running the app again; took me some time to figure this out. Add the following to your info.plist:

<key>NSUbiquitousContainers</key>
<dict>
<key>iCloud.YOUR_BUNDLE_IDENTIFIER</key>
<dict>
<key>NSUbiquitousContainerIsDocumentScopePublic</key>
<true/>
<key>NSUbiquitousContainerSupportedFolderLevels</key>
<string>Any</string>
<key>NSUbiquitousContainerName</key>
<string>iCloudDriveDemo</string>
</dict>
</dict>

Next up, the code:

- (IBAction)btnStoreTapped:(id)sender {
// Let's get the root directory for storing the file on iCloud Drive
[self rootDirectoryForICloud:^(NSURL *ubiquityURL) {
NSLog(@"1. ubiquityURL = %@", ubiquityURL);
if (ubiquityURL) {

// We also need the 'local' URL to the file we want to store
NSURL *localURL = [self localPathForResource:@"demo" ofType:@"pdf"];
NSLog(@"2. localURL = %@", localURL);

// Now, append the local filename to the ubiquityURL
ubiquityURL = [ubiquityURL URLByAppendingPathComponent:localURL.lastPathComponent];
NSLog(@"3. ubiquityURL = %@", ubiquityURL);

// And finish up the 'store' action
NSError *error;
if (![[NSFileManager defaultManager] setUbiquitous:YES itemAtURL:localURL destinationURL:ubiquityURL error:&error]) {
NSLog(@"Error occurred: %@", error);
}
}
else {
NSLog(@"Could not retrieve a ubiquityURL");
}
}];
}

- (void)rootDirectoryForICloud:(void (^)(NSURL *))completionHandler {

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSURL *rootDirectory = [[[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil]URLByAppendingPathComponent:@"Documents"];

if (rootDirectory) {
if (![[NSFileManager defaultManager] fileExistsAtPath:rootDirectory.path isDirectory:nil]) {
NSLog(@"Create directory");
[[NSFileManager defaultManager] createDirectoryAtURL:rootDirectory withIntermediateDirectories:YES attributes:nil error:nil];
}
}

dispatch_async(dispatch_get_main_queue(), ^{
completionHandler(rootDirectory);
});
});
}

- (NSURL *)localPathForResource:(NSString *)resource ofType:(NSString *)type {
NSString *documentsDirectory = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
NSString *resourcePath = [[documentsDirectory stringByAppendingPathComponent:resource] stringByAppendingPathExtension:type];
return [NSURL fileURLWithPath:resourcePath];
}

I have a file called demo.pdf stored in the Documents folder, which I'll be 'uploading'.

I'll highlight some parts:

URLForUbiquityContainerIdentifier: provides the root directory for storing files, if you want to them to show up in de iCloud Drive on your Mac, then you need to store them in the Documents folder, so here we add that folder to the root:

NSURL *rootDirectory = [[[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil]URLByAppendingPathComponent:@"Documents"];

You also need to add the file name to the URL, here I copy the filename from the localURL (which is demo.pdf):

// Now, append the local filename to the ubiquityURL
ubiquityURL = [ubiquityURL URLByAppendingPathComponent:localURL.lastPathComponent];

And that's basically it...

As a bonus, check out how you can provide an NSError pointer to get potential error information:

// And finish up the 'store' action
NSError *error;
if (![[NSFileManager defaultManager] setUbiquitous:YES itemAtURL:localURL destinationURL:ubiquityURL error:&error]) {
NSLog(@"Error occurred: %@", error);
}

Exposing an app's ubiquitous container to iCloud Drive in iOS 8

The catch is to call [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil]; (or with another container identifier if it's not the default one) at least once (not per launch, but presumably per version, or when changing one of the respective PLIST entries) in order to initialize the directory. I reckon this step needs to be combined with an increase of the bundle version number, as suggested in roop's answer.

I notice my question may have been confusing in that respect, as I mentioned being able to look into the documents directory* programmatically using the API in question. However, I removed that code from the app later, maybe before getting the rest of the setup right. I'm not going to write into the documents directory directly, only through the Document Picker. Therefore, there hasn't been any need to get the URL.

If you just need a Document Picker to read/store files from/in iCloud Drive or other apps' document directories, there's no need to call URLForUbiquityContainerIdentifier:. Only if you want your app to have its own ubiquity container (and potentially expose it in iCloud Drive and the Document Picker), the steps mentioned in the original post and the call to URLForUbiquityContainerIdentifier: are necessary.

*When mentioning the documents directory, I'm always referring to the one in the ubiquity container, not the local one.

Swift write/save/move a document file to iCloud drive

I had this problem. I followed the advice here and I found that my Info.plist key was not correct. Once I changed it to iCloud.MY_BUNDLE_IDENTIFIER (i.e. copy the string from the CFBundleIdentifier key higher in Info.plist) it all started working.

Removing the .com from your key may fix your issue.

iCloud Drive on file selection not working

iCloud is only supported on xcode 12.x with IOS 14.X though iCloud is available on xcode 11 but it is not well implemented I guess,

If you are using Catalina, you can use xcode 12.4, more to this version will only supports Bigsure.



Related Topics



Leave a reply



Submit