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

hagi picture hagi · Aug 8, 2014 · Viewed 16.4k times · Source

I'm developing an iCloud-enabled app where users will be able to import and export files via iCloud Drive. When browsing iCloud Drive, either using the UIDocumentPickerViewController (iOS 8) or the Finder (OS X Yosemite), I can see directories created/owned by other iCloud-Drive-enabled apps, such as, Automator, Keynote, or TextEdit.

I want our app to expose its ubiquitous documents directory in iCloud Drive, too, but haven't been able to figure it out yet. Within some of the aforementioned apps' Info.plist files, I've discovered this key:

<key>NSUbiquitousContainers</key>
<dict>
    <key>com.apple.TextEdit</key>
    <dict>
        <key>NSUbiquitousContainerIsDocumentScopePublic</key>
        <true/>
        <key>NSUbiquitousContainerSupportedFolderLevels</key>
        <string>Any</string>
    </dict>
</dict>

These keys are also documented here, but I haven't found any other documentation on the broader subject. Edit/Note: Although it does not contain the answer to my questions, the Document Picker Programming Guide is a helpful resource.

I've tried adding the above-mentioned keys/values to our app but didn't see any effect. Things I've noticed/tried:

  • For 3rd party apps, iCloud containers are constructed this way: iCloud.$(CFBundleIdentifier). I'm not sure why TextEdit only uses the pure bundle identifier, but for our identifier, I've tried both approaches, i.e., with and without the iCloud. prefix. I've also recognised that you need to hard-code the bundle identifier (i.e., don't use iCloud.$(CFBundleIdentifier)) as only the PLIST's values seem to be resolved at build time, but not the keys.

  • I've added a sub-directory programmatically (to <containerPath>/Documents) so the container is not empty. However, this shouldn't matter as all the other apps' directories were initially empty, too.

  • Some Apple apps that appear in iCloud Drive do not have these entries in their Info.plist, e.g., Numbers and Pages.

  • iCloud is set up correctly and I can programmatically look into the ubiquity container using the URL returned by [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil];.

  • I am logged into an iCloud account where iCloud Drive is enabled. I can see my iCloud Drive content in the UIDocumentPickerViewController.

  • I use the iOS 8 beta 5 simulator (and Yosemite beta 5 to view the iCloud Drive directory on the Mac) (Edit/Note: This equally applies to beta 6)

This is how my Entitlements file looks like (relevant parts only)

<key>com.apple.developer.icloud-container-identifiers</key>
<array>
    <string>iCloud.$(CFBundleIdentifier)</string>
</array>
<key>com.apple.developer.icloud-services</key>
<array>
    <string>CloudDocuments</string>
</array>
<key>com.apple.developer.ubiquity-container-identifiers</key>
<array/>

I've set this up using Xcode's UI in the Capabilities section. I don't get why the last key doesn't have an entry, but adding <string>iCloud.$(CFBundleIdentifier)</string> doesn't help. Instead, it makes Xcode complain in the Capabilities UI, so I've removed it. Edit/Note: In Xcode beta 6, this has been fixed, i.e., the ubiquity container identifier needs to be set and Xcode can fix that for you.

Original Questions: So... is it a bug? Does it not work yet? Am I doing it wrong? I couldn't find a known issue in the release notes.

Edit:

Two more things that I've tried:

  • Adding the (optional) NSUbiquitousContainerName key (+ value) to the container-specific dictionary, as suggested by Erikmitk.

  • Adding only the NSUbiquitousContainerIsDocumentScopePublic key/value to the PLIST root dictionary rather than the container-specific dictionary, as it's done in one of the WWDC sample apps (look for NewBox).

Answer

A.C. Wright picture A.C. Wright · Apr 27, 2015

I was experiencing a similar problem with my application. I was able to make this work by doing the following:

  1. Add the NSUbiquitousContainers setting to my Info.plist file according to documentation here https://developer.apple.com/library/prerelease/ios/documentation/General/Conceptual/ExtensibilityPG/FileProvider.html. Here is the relevant code:

    <dict>
        <!-- ... other top-level Info.plist settings ... -->
        <key>NSUbiquitousContainers</key>
        <dict>
            <key>iCloud.com.example.MyApp</key>
            <dict>
                <key>NSUbiquitousContainerIsDocumentScopePublic</key>
                <true/>
                <key>NSUbiquitousContainerSupportedFolderLevels</key>
                <string>Any</string>
                <key>NSUbiquitousContainerName</key>
                <string>MyApp</string>
            </dict>
        </dict>
    </dict>
    
  2. Important! I then changed the above NSUbiquitousContainerSupportedFolderLevels string value from Any to One

    <key>NSUbiquitousContainerSupportedFolderLevels</key>
    <string>One</string>
    
  3. Next, and last, I had to change CFBundleVersion to a higher version. I also bumped the CFBundleShortVersionString to a new version as well.

Built and ran and after that, the folder with my applications icon appeared properly in iCloud Drive! Hope this helps!