Keychain group access to share data between my existing applications

I have many iOS applications live on AppStore. Now for next version of apps, I want to keep a piece of data for every application to share in KeyChain. As far as I know I need to provide same Keychain access group in Apple's KeychainItemWrapper class.

*keychain = [[KeychainItemWrapper alloc] initWithIdentifier:@"Any string" accessGroup:<string representing access group>];

I know about custom URLs and it is of no use as I want data to be persistent.

All my applications have different bundle seed ID as I can see from provisioning portal. I know that the main pre-requisite for shared keychain access is that all of the applications have a common bundle seed ID.

Now my question is how do I make sure that in this senario I can use Keychain to share data among all these applications ?

Is it possible to change the bundle seed ID of all applications through Provisioning profile portal without doing any harm to any functionality ( Although I want to avoid that as there are so many apps).

Is there a way I can add bundle seed ID of all apps in a file and build all apps with that file in project to achieve this ? I know about "keychain-access-groups", do i need to create a plist file and add bundle seed ID of all application in it ?

Appreciate any help in this regard.


Solution 1:

If you have different bundle seed IDs (the ten alphanumeric characters preceding the bundle identifier, the Xs in XXXXXXXXXX.com.company.application), you can't share an access group. It's a restriction on Apple's part and circumventing it is not allowed. I suggest you find another solution of safely sharing data (possibly outside of the device, on a server, but not iCloud as it has the same restrictions).

General information about keychain access groups:

Since iPhone OS 3.0 it has been possible to share data between a family of applications. This can provide a better user experience if you follow the common path of free/premium applications or if you have a set of related applications that need to share some common account settings.

The main pre-requisite for shared keychain access is that all of the applications have a common bundle seed ID. To be clear what this means remember that an App ID consists of two parts:

<Bundle Seed ID> . <Bundle Identifier>

The bundle seed ID is a unique (within the App Store) ten character string that is generated by Apple when you first create an App ID. The bundle identifier is generally set to be a reverse domain name string identifying your app (e.g. com.yourcompany.appName) and is what you specify in the application Info.plist file in Xcode.

So when you want to create an app that can share keychain access with an existing app you need to make sure that you use the bundle seed ID of the existing app. You do this when you create the new App ID in the iPhone Provisioning Portal. Instead of generating a new value you select the existing value from the list of all your previous bundle seed IDs.

One caveat, whilst you can create a provisioning profile with a wildcard for the bundle identifier I have never been able to get shared keychain access working between apps using it. It works fine with fully specified (no wildcard) identifiers. Since a number of other Apple services such as push notifications and in-app purchase also have this restriction maybe it should not be a surprise but I am yet to find this documented for keychain access.

Once you have your provisioning profiles setup with a common bundle seed ID the rest is pretty easy. The first thing you need to do is register the keychain access group you want to use. The keychain access group can be named pretty much anything you want as long as it starts with the bundle seed ID. So for example if I have two applications as follows:

ABC1234DEF.com.useyourloaf.amazingApp1

ABC1234DEF.com.useyourloaf.amazingApp2

I could define a common keychain access group as follows:

ABC1234DEF.amazingAppFamily

To enable the application to access this group you need to add an entitlements plist file to the project using xCode. Use Add -> New File and select the Entitlements template from the iPhone OS Code Signing section. You can name the file anything you like (e.g. KeychainAccessGroups.plist). In the file add a new array item named keychain-access-groups and create an item in the array with the value of our chosen keychain access group:

Note: Do not change the get-task-allow item that is created by default in the entitlements file unless you are creating an Ad-Hoc distribution of your app (in which case you should uncheck this option).

This same process should be repeated for all apps that share the bundle seed ID to enable them to access the keychain group. To actually store and retrieve values from this group requires adding an additional value to the dictionary passed as an argument to the keychain services. Using the example from the previous post on simple iPhone keychain access the search dictionary gets the following additional item:

[searchDictionary setObject: @"ABC1234DEF.amazingAppFamily" forKey: (id)kSecAttrAccessGroup];

One final comment, using a shared keychain access group does not stop you from storing values in an applications private keychain as well. The Apple GenericKeychain example application builds two applications which both store data in a private and group keychain.

Source: Use Your Loaf

Solution 2:

Now you can use UIPasteboard

//First app, install->run->close->delete
UIPasteboard* board = [UIPasteboard pasteboardWithName:@"com.company.wtv" create:YES];
board.persistent=YES;// persistent to make what you write persist after your app closes, or gets deleted.
[board setValue:@"ccccc" forPasteboardType:@"com.company.wtv.sharedValue"];

//Second app, installed after first one is deleted and ran this one... While bundle identifier and bundle seed different (i tried it on adhoc, not really releasing the app, but i htink the same)
NSData* result=nil;
NSString*resultStr=nil;
result =[board valueForPasteboardType:@"com.company.wtv.sharedValue"];
resultStr=[[NSString alloc] initWithData:result encoding:NSUTF8StringEncoding];// I got resultStr containing ccccc

check UIPasteboard documentation for further info. I'll be coming back after using this for my store apps, in case of troubles