I have been experimenting with iCloud sample code and tutorials in order to develop a syncing system between our MacOS and iOS products. On the iOS side I have had no problem building and running code that manipulates data in an iCloud Documents container, but on the MacOS side, using the Apple MacOS PackagedDocument sample project, I have not been able to successfully place any data in my iCloud. I believe the basic problem is that the URLForUbiquityContainerIdentifier for my app can not be found, probably due to some error in iCloud entitlements specification. But, after much time spent fiddling with the developer portal and Xcode 6/PackagedDocument settings, I have been unable to locate the source of the problem.
My iCloud account was previously a MobileMe account and is used to synchronize the Apple apps between MacOS and iOS devices, so I believe my iCloud account is working without problems.
Here I am illustrating the different ways that I have specified the call to get the iCloud Documents container. The call to get the iCloud container URL returns nil regardless of how it is specified:
// remember our ubiquity container NSURL for later use
_ubiquityContainer = [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:@"icloud.com.mycompany.PackagedDocument"];
_ubiquityContainer = [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:@"7G3Z4SV5WT.com.mycompany.PackagedDocument"];
_ubiquityContainer = [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil];
In my iOS experiments, this URLForUbiquityContainerIdentifier call always gets the desired URL.
The CFBundleIdentifier for the app is com.mycompany.PackagedDocument
The iCloud entitlement keys are specified as follows:
The com.apple.application-identifier key value is $(TeamIdentifierPrefix)com.mycompany.PackagedDocument
The com.apple.developer.icloud-services key value is CloudDocuments
The com.apple.developer.icloud-container-identifiers key value is iCloud.$(CFBundleIdentifier)
and the com.apple.developer.ubiquity-container-identifiers key value is iCloud.$(CFBundleIdentifier)
I also tried code from this video tutorial, but get the same nil result when trying to get the ubiquity container:
- (IBAction)saveToIcloud:(id)sender {
NSFileManager *fm = [NSFileManager defaultManager];
NSURL *directory = [[fm URLForUbiquityContainerIdentifier:@"7G3Z4SV5WT.com.mycompany.PackagedDocument"]
URLByAppendingPathComponent:@"Documents"];
directory = [[fm URLForUbiquityContainerIdentifier:@"iCloud.com.mycompany.PackagedDocument"]
URLByAppendingPathComponent:@"Documents"];
directory = [[fm URLForUbiquityContainerIdentifier:nil]
URLByAppendingPathComponent:@"Documents"];
directory = [[fm
if (directory) {
[fm createDirectoryAtURL:directory withIntermediateDirectories:NO attributes:nil error:NULL];
NSURL *filepath = [NSURL URLWithString:@"/Users/leg/Desktop/myjpeg.jpg"];
NSURL *destination = [directory URLByAppendingPathComponent:[filepath lastPathComponent]];
[fm setUbiquitous:YES itemAtURL:filepath destinationURL:destination error:nil];
}
}
In summary, I believe the problem must have something to do with my specification of iCloud entitlements and/or other specifications necessary to access iCloud Document containers. If anyone has a clue about what may be happening to me, I'd greatly appreciate their feedback. Failing that, maybe someone could point me at working non-iOS, macos iCloud Documents sample code.
Additional Information
I am seeing the following messages in he console log PackagedDocument start-up:
9/2/15 5:19:11.966 PM taskgated-helper[14145]: unsatisfied entitlement com.apple.developer.ubiquity-container-identifiers
9/2/15 5:19:11.966 PM taskgated-helper[14145]: unsatisfied entitlement com.apple.developer.icloud-container-identifiers
9/2/15 5:19:11.966 PM taskgated-helper[14145]: unsatisfied entitlement com.apple.developer.ubiquity-container-identifiers
9/2/15 5:19:11.966 PM taskgated-helper[14145]: unsatisfied entitlement com.apple.developer.icloud-container-identifiers
9/2/15 5:19:11.966 PM taskgated-helper[14145]: unsatisfied entitlement com.apple.developer.ubiquity-container-identifiers
9/2/15 5:19:11.966 PM taskgated-helper[14145]: unsatisfied entitlement com.apple.developer.icloud-container-identifiers
9/2/15 5:19:11.967 PM taskgated-helper[14145]: allowing entitlement(s) for pid=14144 due to provisioning profile
More Information
I performed an experiment with a working iOS iCloud example project to validate the PackagedDocument iCloud container:
I altered the iOS example’s Capabilites/iCloud settings from “Use default container” to “Specify custom containers”. I checked off the example’s default container and checked on “iCloud.com.mycompany.PackagedDocument”.
I then changed the URLForUbiquityContainerIdentifier call:
from: NSURL *baseURL = [[NSFileManager defaultManager]URLForUbiquityContainerIdentifier:nil];
to: NSURL *baseURL = [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:@"iCloud.com.mycompany.PackagedDocument"];
Now, when I run this iOS app, it creates the PackagedDocument iCloud container and uses it for its data—-exactly what I’ve been trying to do with the PackagedDocument MacOS sample.
I then went back to the MacOS PackagedDocument project and ran it to see if the URLForUbiquityContainerIdentifier call would now find the container. It did not. Nil is still returned even though the container definitely now exists.
I suppose that this means it is still an entitlements problem of some kind.
Even More Information
I performed another experiment whereby I exported my developer identities from Xcode 6.4/Preferences/Actions/Export Accounts… of my usual developer system (Yosemite 10.10.5,) and then rebooted my MacBook Pro under Mavericks 10.9.5 and imported the identities with Xcode 6.1/Preferences/Actions/ Import Accounts…. (The Mavericks system disk is actually a Carbon Copy of my MacBook Pro system disk before I upgraded it to Yosemite.) Now, when I build and run PackagedDocument in Mavericks, everything works perfectly.
I then rebooted back into Yosemite and removed my identities and imported the identities with Xcode 6.1/Preferences/Actions/ Import Accounts…. Now, when I build and run PackagedDocument in Yosemite, it still does not work--does not find the iCloud container.
I then decided to try the same experiment in a clean install of El Capitan (10.11 Beta 5)/Xcode 6.4. Again, it still does not work--does not find the iCloud container.
And finally, I decided to try one more experiment. I decided to try turning on iCloud Drive. But, because I did not want to convert my working iCloud account to iCloud Drive, I decided to create a new iCloud ID for the test, and to turn on iCloud Drive. Now, when I build and run PackagedDocument in El Capitan with iCloud Drive, everything works perfectly.
Why does Apple's PackagedDocument MacOS iCloud sample project not find URLForUbiquityContainerIdentifier?
The Even More Information which I added to the end of my question has lead me to the conclusion that iCloud Drive is now required for a non-apple app to access iCloud containers if the MacOS is greater than 10.9 (Mavericks,) i.e. Yosemite or El Capitan. That is, the URLForUbiquityContainerIdentifier will not be found in plain iCloud Yosemite or El Capitan. I think it is significant that PackagedDocument works fine in pre-iCloud Drive Mavericks, and seems to work fine in an iCloud Drive El Capitan, (but not in a plain iCloud El Capitan.)
I suppose there must be some mechanism for grandfathering plain iCloud-using pre-Yosemite apps so they can still create and access their iCloud containers, but I don't know what it is.