My app crashes with an "Application initializing document picker is missing the iCloud entitlement" when either of the following two lines is executed:
UIDocumentPickerViewController* documentPicker =
[[UIDocumentPickerViewController alloc]
initWithDocumentTypes:@[@"public.data"]
inMode:UIDocumentPickerModeImport];
UIDocumentMenuViewController *documentMenu =
[[UIDocumentMenuViewController alloc]
initWithDocumentTypes:@[@"public.data"]
inMode:UIDocumentPickerModeImport];
The Document Picker Programming Guide states that "Before your app can use the document picker, you must turn on the iCloud Documents capabilities in Xcode."
However, my app is not built with Xcode: it is built using third-party tools (the cross-platform toolkit, Marmalade), so I cannot do this.
It should still be possible to turn on iCloud Documents capabilities for this app manually — the switch in iCloud simply automates the process — but my attempts to do so have not fixed the crash.
Xcode displays the steps it carries out when switching on iCloud:
I also found Apple's Entitlements Troubleshooting TechNote, which describes steps that can be taken to check that the following steps have been carried out correctly.
I have enabled iCloud on my App ID:
I'm not certain whether this is necessary to use the document picker's simple import and export operations, but I also set up an iCloud container with the id iCloud.com.[company].[app]
.
I have generated an updated provisioning profile that includes the iCloud entitlements:
I inspected the downloaded provisioning profile using the command:
security cms -D -i /path/to/iOSTeamProfile.mobileprovision
It includes the following entries:
<key>com.apple.developer.icloud-services</key>
<string>*</string>
<key>com.apple.developer.icloud-container-environment</key>
<array>
<string>Development</string>
<string>Production</string>
</array>
<key>com.apple.developer.icloud-container-identifiers</key>
<array>
<string>iCloud.com.[company].[app]</string>
</array>
<key>com.apple.developer.icloud-container-development-container-identifiers</key>
<array>
<string>iCloud.com.[company].[app]</string>
</array>
<key>com.apple.developer.ubiquity-container-identifiers</key>
<array>
<string>iCloud.com.[company].[app]</string>
</array>
Marmalade uses this provisioning profile to generate the entitlements file for the app.
I have inspected the generated entitlements using the following command:
codesign -d --ent :- [App.app]
Which gives the following output:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>application-identifier</key>
<string>[team-id].com.[company].[app]</string>
<key>aps-environment</key>
<string>development</string>
<key>com.apple.developer.icloud-container-development-container-identifiers</key>
<array>
<string>iCloud.com.[company].[app]</string>
</array>
<key>com.apple.developer.icloud-container-environment</key>
<array>
<string>Development</string>
<string>Production</string>
</array>
<key>com.apple.developer.icloud-container-identifiers</key>
<array>
<string>iCloud.com.[company].[app]</string>
</array>
<key>com.apple.developer.icloud-services</key>
<string>*</string>
<key>com.apple.developer.team-identifier</key>
<string>[team-id]</string>
<key>com.apple.developer.ubiquity-container-identifiers</key>
<array>
<string>iCloud.com.[company].[app]</string>
</array>
<key>com.apple.developer.ubiquity-kvstore-identifier</key>
<string>[team-id].*</string>
<key>get-task-allow</key>
<true/>
<key>keychain-access-groups</key>
<array>
<string>[team-id].com.[company].[app]</string>
</array>
</dict>
</plist>
However, the app still crashes whenever the functions are called.
I also found this old guide to setting up iCloud in Marmalade apps. Most of the steps seem no longer to be necessary/possible, but I followed the suggestion to add the application-identifier
key to my Info.plist.
What else do I need to do to add iCloud Documents capabilities to my app?
Marmalade generates the .xcent
entitlements file used when signing the app by copying over the "Entitlements" dict
from the provisioning profile.
The problem was caused by the value associated with the undocumented key:
<key>com.apple.developer.icloud-services</key>
<string>*</string>
This appears to be valid in the provisioning profile, but invalid when signed into the app. Replacing those elements in the generated .xcent file
with the following and then re-signing the app fixed the issue:
<key>com.apple.developer.icloud-services</key>
<array>
<string>CloudDocuments</string>
</array>
(N.B. If you also use CloudKit, you will also need to add a CloudKit
string
to the array
.)
In practice, we fixed this by editing Marmalade's sign_app.py
script to use a pre-prepared .xcent
file (copied over from the DerivedData
directory of the functioning app we built with Xcode) when signing the app:
In file /Applications/Marmalade.app/Contents/s3e/deploy/plugins/iphone
edit line 557:
cmd += ['--entitlements', xcentfile.name]
...replacing xcentfile.name
with the path to the pre-prepared .xcent
file.