I've worked for a while now on my (existing) app to add support iCloud synchronization. In total, I have 3 Versions of the app:
a) regular iPhone version
b) lite (free) iPhone version
c) iPad version
I want to use iCloud to make the core data storage sync between all 3 versions/devices. I've got the implementation, and the development versions I put on my devices worked great.
Yesterday I decided to submit the iPhone versions, but they got rejected:
Invalid Code Signing Entitlements - The signature for your app bundle contains entitlement values that are not supported. For the com.apple.developer.ubiquity-container-identifiers entitlement, the first value in the array must consist of the prefix provided by Apple in the provisioning profile followed by a bundle identifier suffix. The bundle identifier must match the bundle identifier for one of your apps or another app that you are permitted to use as the iCloud container identifier.
Specifically, value "[teamid].com.[myself].[somename]" for key "com.apple.developer.ubiquity-container-identifiers" in [my app] is not supported.
I really have no clue about how those identifiers should look like. On this page: https://developer.apple.com/library/ios/#documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/iCloud/iCloud.html#//apple_ref/doc/uid/TP40007072-CH5-SW1 they say something about containers of my other apps ... do I have to add 3 containers for the 3 versions of my app? So far I configured under project/targets/summary/entitlements:
[x] iCloud Key-Value Store: com.[myself].[somename]
iCloud Containers: com.[myself].[somename]
for all 3 versions (same identifiers). What do I have to configure exactly, so that all 3 versions will sync their core data storage database through iCloud?
According to iCloud Design Guide: iCloud Fundamentals, all your apps sharing your iCloud container, can do so using a single iCloud container (if that is what you wish). The catch here is that the primary (first) container ID must be the Bundle ID of your current app being developed, or a Bundle ID of any of your previously submitted apps (that share the same Team ID).
I'll bring an example,
Let us assume that your app regular iPhone app (a) has a Bundle ID com.yourteam.iphoneapp and it was the one that you submitted first and is available on the App Store. Then you have to provide that same ID as the primary iCloud container ID for all other versions as well.
Here's a relevant section out of the document mentioned above:
In the Xcode target editor’s Summary tab, you can request access to as
many ubiquity containers as you need for your app. For example, say
you provide a free and paid version of your app. You’d want users, who
upgrade, to retain access to their iCloud documents. Or, perhaps you
provide two apps that interoperate and need access to each other’s
files. In both of these examples, you obtain the needed access by
specifying a common ubiquity container and then requesting access to
it from each app.
Pick one of your iCloud-enabled apps to serve as the primary app for the common ubiquity container. The app you pick can be the current
one you are developing, or another app of yours submitted for
distribution in the App Store and whose entitlements use the same team
ID.
You have probably resolved this issue by now, but the answer is that you just use the same ubiquity container identifier in all apps. You only need one, and it is not dependent on the app name: notice Apple told you to use "[teamid].com.[myself].[somename]" not "[teamid].com.[myself].[appname]". Use "some name" that is consistent between the apps, not the "app name".
You need to create 3 separathe iCloud enabled provisional profiles. Devices that are running the same version of your app can share data on the same iCloud container. But if you wish to have any devices running any one of those three versions of your apps to share data then you need to add those identifiers in the Entitlements section of each version.
There is good tutorial on iCloud from http://www.raywenderlich.com/6015/beginning-icloud-in-ios-5-tutorial-part-1
Edited:
I added an sample picture for your case. Also, the text below is extracted from the tutorial on that website:
Here we use a new method you haven’t seen yet called URLForUbiquityContainerIdentifier. This method allows you to pass in a container identifier (like you set up earlier in the iCloud Containers section) and it will return to you a URL to use to access files in iCloud storage.
You need to call this on startup for each container you want to access to give your app permission to access the URL. If you pass in nil to the method (like we do here), it automatically returns the first iCloud Container set up for the project. Since we only have one container, this makes it nice and easy.
Related
We recently integrated UICloudSharingController to share cloudkit records on one of our apps, but we noticed while testing that the icloud share link opens the wrong app on App Store if we invite a participant who has not the app installed on his device. We thought it was because we basically duplicated the same coredata/cloudkit implementation for another our app (app store opens the download page for this app), forgetting maybe some cloudkit references of the first app and indeed we noticed a wrong icloud container assignment for the second app, which essentially had two containers, the correct one (its own) and the one of the first app (the wrong one). So, we fixed the problem, every app has his own container now and only his own, and we updated the provisional profiles as well, in order to have the correct icloud containers entitlements. Unfortunately the problem persists and after check everything else (containers, app groups, PersistentStoreDescriptions etc.) we don't have any more ideas.
What else should we check? Thanks in advance for your suggestions.
Some more details of the issue:
If we have the app installed on the device the icloud share link opens the right app.
The same icloud share link works properly on Mac Catalyst (the App Store opens the correct app page if we don't have the app installed). The problem is only on iOS.
Could you check the following:
1. Bundle ID and CloudKit Container ID
Check if the Bundle ID and CloudKit Container IDs fully qualified and match on the original app
The 2nd app should have a different Bundle ID and Container ID from the original app.
How is the CKContainer created, is it using any identifier? If so does identifier correct?
I feel that some how the problem arises because the projects were duplicated and then modified, that is not a good idea as bundle settings, info.plist, entitlements would be reused.
2. CKSharingSupported
In your plist, is CKSharingSupported set to true for the other app?
CKSharingSupported should be turned on only on the app that needs to support sharing
Refer https://developer.apple.com/documentation/bundleresources/information_property_list/cksharingsupported)
3. Create a new project
Try with a simple app and ensure Share works as you would expect
Copy code (not the info.plist or the entitlements) and build on it incrementally instead of doing it all in one shot
I'm stuck in a slightly weird situation. When our app was first created, nobody really knew what they were doing and I'm trying to clean things up a bit.
In the iOS developer center, it seems that there are two App IDs for my app. I think I can delete one of them, because the other one is the one that is actually being used, but I'm not 100% sure.
Here is the App ID that I think is actually being used in our released app:
Here is the "other App ID":
The annoying thing is that the "other App ID" seems to match the bundle ID of the app and xCode seems to be trying to use it as the application-identifier when the app is submitted to the store. I don't want the application identifier to change.
Is it safe to delete the other app id? Can I force xCode to use the correct application identifier? How can I tell which app ID is actually being used by our released app?
Edit:
Why this arose is because after submitting our latest build to the store for testflight, I got this notification:
Dear developer,
We have discovered one or more issues with your recent delivery for
"My Cool App". Your delivery was successful, but you may wish to
correct the following issues in your next delivery:
Potential Loss of Keychain Access - The previous version of software
has an application-identifier value of ['ABCDE.MyCoolApp'] and the new
version of software being submitted has an application-identifier of
['QWERTY.MyCoolApp']. This will result in a loss of keychain access.
After you’ve corrected the issues, you can use Xcode or Application Loader to upload a new binary to iTunes Connect.
Regards, The App Store team
The fact that the application-identifier is changing, and that it appears to be using the "prefix" as part of this value, suggests that it was using the first app ID, but now it is going to use the second.
Do you have access to login in to the iTunes Connect for that account? That's what you really need to verify the bundle ID (aka app ID) of the released app.
Login at itunesconnect.apple.com, click on apps, click on your specific app, click on the 'more' tab, click on 'about this app' it will show you the bundle ID being used for the released app. Feel free to delete the OTHER app ID out of your account. Not the one in iTunes Connect :)
The bundle ID in your Xcode project can always be modified to match whatever app ID you'd like, as well as you can easily regenerate any necessary provisioning profiles for any app ID. (of course, you should make it match the existing one in iTunesConnect if you want to release an update for that app)
Edit:
It sounds like you've been able to match up the app ID, but not the prefix. The way prefixes are assigned has changed over the years and now they are all team based. You can read this technical note and see if it will help you resolve the warning you encountered.
Developer Link
The primary difference between your 2 App ID is the ID:
the first one has '*' as ID. It means it is a wildcard ID. You can create multiple applications using different bundle identifiers with the same provisioning profile using this ID. But you don't have access to specific capabilities such as Push Notifications, in-app purchase (because multiple apps will share the same profile
the second one is fully qualified and can be used only with the app whose bundle identifier is 'MyCoolApp' and can have access to full capabilities of apps.
Note that your app ID naming convention should be in reverse url format as Apple advices: myCompany.myInternalGroup.myAppId.appFlavor for instance.
I am developing a program where I need to store a unique device_id since I cant get a unique identifier (like MAC Address) for every device, because it is deprecated by Apple.
What I want to do is, store a file in a specific directory of iOS where even the user deletes my iOS app this file wont be deleted. I am saying this because I used NSUserDefaults but the data stored from it get deleted if the user deletes its application.
*P.S Or if there is an alternative way to identify every device with its unique_id, suggestions are welcomed!*
You should use KeyChain to save info that should not be deleted together with app.
https://developer.apple.com/library/ios/documentation/Security/Reference/keychainservices/Reference/reference.html
UPDATE
This SO thread could be useful for you Saving/Reading to/from KeyChain
I need to store a unique device_id since I cant get a unique
identifier
It is not 100% correct. You can use
[ UIDevice currentDevice ].identifierForVendor
From Apple's docs :
The value of this property is the same for apps that come from the
same vendor running on the same device. A different value is returned
for apps on the same device that come from different vendors, and for
apps on different devices regardless of vendor.
Normally, the vendor is determined by data provided by the App Store.
I the app was not installed from the app store (such as enterprise
apps and apps still in development), then a vendor identifier is
calculated based on the app’s bundle ID. The bundle ID is assumed to
be in reverse-DNS format.
On iOS 6, the first two components of the bundle ID are used to
generate the vendor ID. if the bundle ID only has a single component,
then the entire bundle ID is used. On IOS 7, all components of the
bundle except for the last component are used to generate the vendor
ID. If the bundle ID only has a single component, then the entire
bundle ID is used.
I have an app published on the AppStore and I want to migrate it to an enterprise developer account for in-house distribution. I read in the enterprise documentation that:
If you want users to keep the app’s data stored on their device, make sure the new version uses the same bundle-identifier as the one it’s replacing, and tell users not to delete their old version before installing the new one. The new version will replace the old one and keep data stored on the device, if the bundle-identifiers match.
Now, assuming we keep the Bundle ID the same between the AppStore binary already installed and the enterprise binary signed with a different certificate... it should overwrite the same app on their phone rather than create a second app.
I contacted Apple support and they said "No, you will have 2 apps installed if you do not instruct the clients to uninstall their old one". Is this true?
EDIT: I'm leaving my original answer below for conversations sake as there is good dialogue below. As #mja noted when you initially create an app ID it is associated with one of a few available prefixes to your developer portal and that prefix may be used by iOS to associate & differentiate between apps.
EDIT2: When I go into my Enterprise Portal and try to create an app ID with an identical value to an existing app ID but with a different prefix it still blows up on me and says:
An App ID with Identifier 'com.mycompany.myapp' is not available.
Please enter a different string.
ORIGINAL Answer:
The latter part is incorrect - iOS devices use the Bundle Identifier to differentiate between apps. I can have 20 apps labeled "Cool App" on the same iOS device so long as they have unique bundle identifiers such as com.mycompany.coolapp.1 - com.mycompany.coolapp.20. Likewise (and I've done this accidentally) if I open two projects, both of which have bundle identifiers com.mycompany.myapp, and run one right after the other the last app to be run will be installed on the device whereas the previous app will be overwritten.
Regarding the app data sustaining itself I have not tested that though I'd be interested in what happens for you!
I have managed to achieve this, so that the 'enterprise' build of the app overwrites an 'app store' distributed version.
This does not use the exact same bundle ID but does achieve what OP asked in his original question.
How I did this was, in my enterprise account, create a wildcard bundle identifier with the first two parts the same as the bundle identifier for our production app, for example:
Production : com.xyz.abc
Enterprise : com.xyz.*
Using this wildcard bundle ID, the app can be distributed and will overwrite any versions installed via the app store (user data will still persist). The prefix does not seem to matter here.
One drawback of the wildcard bundle id is the fact that you cannot use APNS etc.
A few quick questions on App ID's / Submission if you don't mind,
1: Can many App ID's can be added to the same provisioning/distribution profile? - so apps with different app ids can be distributed to the store with the same distribution profile?
2: Can you release an app to the store with a wildcard app id?
3: Does enabling services on an app id just allow you to use for example iCloud apis? If they weren't enabled would iCloud Apis (for example) just be ignored in the app?
4: When I was submitting my app last night, iTunes Connect needed a bundle id, which I set to say "com.John.myApp" -- when I was validating my app it said that my Apps bundle Id in xcode had to match "com.John.myApp" that I set in iTunes connect....
However in xcode my bundle id was something bigger like: "com.John.${PRODUCT_NAME:rfc1034identifier}"
so I just set it to "com.John.myApp" is that ok?
Thanks all,
Use a wildcard profile.
Yes.
It depends on the service, and some services won't work with a wildcard profile.
Yes. The default you replaced is just a default, a lot of people will have the app name in the bundle I'd but you don't have to.