Keychain group access to share data between my existing applications - iphone

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.

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

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

You can't change your app's bundle ID after it has been put into the AppStore. You also can't make an app read the info from the keychain that was put there by another app (with a different bundle ID). The solution: you'll need an entitlement with which you can access practically all the data.

Related

Manage iOS Enterprise Developer Program

We recently enrolled in the iOS Enterprise Developer Program to be able to use in-house distribution, which significantly simplifies the deployment of the apps inside our company which is fairly big. Before joining we have thoroughly read the program documentation and we were aware that the new account would live completely separated from the standard account we use for the AppStore submissions.
What I'm unsure about is now what would be the best way to organize the two accounts in the developer portals. I'm mostly concerned with the bundle identifier since I'll be dealing with two different bundle ids inside Xcode for each application. All of our apps use iCloud and Push notifications so wildcard is not an option.
How do you organize this inside Xcode? Do you create two different targets or are you able to manage this with a new Project Configuration? What about iCloud entitlements?
EDIT
Just as an update I wanted to make clear that we're looking for the best solution to build an app for both In-House distribution and for AppStore submission.
EDIT2
Given that the enterprise program does not grant you access to iTunesConnect, where test users and product ids can be setup, is there really no way to test InApp purchases?
I'm not entirely clear on what you need, but it sounds like you want to be able to build your app store apps for internal enterprise use. Is that correct?
If you want to be able to build your app with two different bundle IDs you can create a custom build setting, and give it different values for your different configurations.
So for example, you could create your Enterprise configuration:
Then go to your target's build settings and add a user-defined build setting:
Give it a name like BUNDLE_ID, and if you expand the triangle you can give it different values for each configuration:
Next, open your Info.plist file and enter ${BUNDLE_ID} for the bundle id value:
When you compile using the "Enterprise" configuration, which you can do using a custom scheme (or via the command line build process if that's what you use), the appropriate bundle id will be used.
You can also configure the code signing/provisiong profile setting in the same way:
Once you do this, the correct push notification/iCloud entitlements will be used depending on the configuration.
We've been doing this kind of thing for a long time now. Our build server will generate enterprise and app store versions of our apps for each build, using exactly this technique.
When it comes to the provisioning portal, you will need to configure both app IDs separately for push notifications, iCloud, etc.
This does mean that push notifications must be sent separately to the app store and enterprise versions since they will not share the same bundle ID or push notification certificate.
The iCloud storage by default will be totally separate for the two versions. They may be able to access the same iCloud store (if you need this) as long as the entitlements are set up with the same team ID. But this may be a problem if you have two separate developer accounts.

Building and testing multiple apps - trying to understand appID's and profiles

I'm trying to understand app ID's and provisioning profiles here, I'm quite lost.
I am a registered Apple Developer as an individual under my full name, and I have 2 applications currently in the works, and 2 device UDID's ready for testing.
I'd like to be able to build IPA's for these two apps, upload them to TestFlight, and use them on either of the UDIDs I have on me.
I have several questions (if I should ask separate questions, I'd be happy to unless someone happens to be willing to answer them, I'd appreciate it):
1) Because I have 2 (or more in the future) applications, do I need a wildcard app ID?
2) If I have the app ID ET9WC78H9Q.com.mydevname.* listed in the portal - WHAT is the actual appID - ET9WC78H9Q.com.mydevname.*, ET9WC78H9Q.com.mydevname, or *?
3) Why can't you delete an AppID in the portal?
4) I've read that this must match the name Bundle Identifier. Currently it sits at ${PRODUCT_NAME:rfc1034identifier}. What specifically needs to go here to 'match'?
5) Do I need to create separate distribution profiles for each app, or can I tell each new app to use the wildcard identifier?
6) How do I tie a specific target to a specific provisioning profile in XCode 4? (TestFlight suggests to use the distribution profile)
Thank you,
You have to either have a wildcard app id, or 2 separate (specific, non-wildcard) app ids, one each.
That is a wildcard app id, so the app id is *
No idea.
Your PRODUCT_ NAME, which you specify in the Packaging section of the Build Settings screen.
A single distribution profile will work with multiple apps if the app ID for that profile is a wild-card app id. If they are specific app IDs, yes, you need a profile for each app.
You specify the provisioning profile in the Code Signing section of Settings, under CODE_SIGN_IDENTITY.
Because I have 2 (or more in the future) applications, do I need a wildcard app ID?
You don't. In fact, I recommend against it, since it's probably only going to give you problems with the App Store in the future.
If I have the app ID ET9WC78H9Q.com.mydevname.* listed in the portal - WHAT is the actual appID - ET9WC78H9Q.com.mydevname.*, ET9WC78H9Q.com.mydevname, or *?
That depends on the application. The first part is the Keychain space, which determines which applications can access the things you put in the Keychain. Then comes the actual application identifier, which is generally company.projectname. It would probably be ET9WC78H9Q.com.mydevname.myapplication in your case.
Why can't you delete an AppID in the portal?
On Mac and iOS, the AppID is very important for applications like the App Store. They have to be unique, since having two of them could mean that applications get installed in the wrong place. This means that even if you could remove them you couldn't ever add them again, which means there's no point in deleting them.
I've read that this must match the name Bundle Identifier. Currently it sits at ${PRODUCT_NAME:rfc1034identifier}. What specifically needs to go here to 'match'?
Wouldn't worry too much about that - simply look at the target summary page (click the solution then click the target and finally go to the summary tab) and it'll tell you the name it automatically picked for you.
Do I need to create separate distribution profiles for each app, or can I tell each new app to use the wildcard identifier?
You can definitely use the wildcard identifier, but the App Store will not necessarily like that.
How do I tie a specific target to a specific provisioning profile in XCode 4? (TestFlight suggests to use the distribution profile)
Wouldn't worry too much about that. If you got the code signing set up correctly (look at the build settings, then pick the development and deployment certificates) then you have nothing to worry about.
Can't say much more in here since most App Store things are guarded by an NDA. Consider asking this on https://devforums.apple.com instead.

How is application ID used by Xcode when building/signing the application?

iOS Provisioning files make reference to the Apple application ID (of the form "A1A2A3A4A5"). Most often, the DNS form of the application is replaced with a star (*).
My understanding is that the provisioning profile is stored in the iOS development device and is not used by Xcode. Thus, when building/signing the application, how can Xcode include the app ID into the executable file ? The only information Xcode has is the "Bundle Identifier", which is of the form "com.mycompany.myapp" - but there is no App ID, thus there is no way to add the app ID at this stage.
Does anyone know how this works. I feel that many people use those tools (as I do) without really knowing how it's made inside.
Many Regards,
Apple92
An iPhone application is not just an executable, it's a bundle (like a directory) that contains the executable, but also resources (like nibs or images) and in particular contains a small plist manifest file with details about your application - including the application ID. The provisioning profile is also included in this application bundle.
A device also maintains a list of provisioning profiles it has installed, but the profiles can be in the application as well and are checked against the application plist file to make sure everything matches.
For anyone who may stumble upon this question, I give a lot of detailed context in my answer to this related question.
https://stackoverflow.com/a/20557213/117471
Basically it boils down to this:
A Bundle ID is a string that is defined in Xcode
An App ID is an object that lives in Developer Member Center. It is often confused with Bundle ID because the App ID Suffix parameter of the object (I'm trying to drive home the fact that App ID is not a string. Is it working?) matches the Bundle ID of your app.
The App ID does not exist in iTunes Connect, or Xcode. It is only in Developer Member Center.

Is it possible to bundle a unique file for each copy of iPhone app downloaded from App Store?

I would like to verify the identity of each instance of the iPhone application that a user might use to connect to my service. To that end, I would like each instance of the iPhone app downloaded to include a certificate that I generate, or even some sort of UUID that I have generated. Does the App Store support the inclusion of unique files in an app bundle?
Or, must such identifiers be downloaded only after the app is installed? If that is the case, is there a mechanism to ensure that the app downloaded is trusted (from me), instead of from an impersonator?
I don't think it's possible to have unique packages per download. Why don't you use the UUID of the device for such checks?

How to use another app's settings

What code could I use in an iPhone app to get and set the settings of another app I wrote? (preferably using NSUserDefaults)
You're not going to be able to pull this off with NSUserDefaults.
The Keychain, while somewhat cumbersome in its C-ness and much more limited than the NSUserDefaults API, might allow you to accomplish this. If you can serialize whatever you need to share between your apps into a few strings, it might be worth trying.
From iPhone OS 3.x Release Notes:
It is now possible for you to share Keychain items among multiple applications you create. Sharing items makes it easier for applications in the same suite to interoperate more smoothly. For example, you could use this feature to share user passwords or other elements that might otherwise require you to prompt the user from each application separately.
Sharing Keychain items involves setting up the proper entitlements in your application binaries. Using Xcode, you must create an Entitlements property list file that includes the supported entitlements for your application. The process for creating this file is described in iPhone Development Guide. For information about the entitlements you can configure, see the description for the SecItemAdd function in Keychain Services Reference.
Accessing shared items at runtime involves using the Keychain Services programming interface with the access groups you set up during development. For information about how to access the Keychain, see Keychain Services Programming Guide.
Here's Buzz Anderson's Simple iPhone Keychain Code. You could use it to store key/value pairs as strings in the keychain. It's not much, but perhaps better than nothing. See Apple's Keychain Programming Guide for more.
You simply cannot do that. Each application is installed into its own folder and is given its own, unique user id. The file containing these settings is in the other application's folder and its permissions are set to that of the other application. The only way to access the data is to use the same application identifier as the other application, in which case installing your application would overwrite the old application.
EDIT:
This solution was given when the question was asking to do this using NSUserDefaults, specifically. For the updated question, the keychain approach or the server approach provided are both reasonable.
You can have one app send the data to your server, then the other app can get the data from your server.
You can't do this using NSUserDefaults but it can be done.
You could use a shared clipboard. It wouldn't be secure, but both apps could read and write from the same clipboard. You just need to create an application specific UIPasteboard. Check out the UIPasteboard class reference on Apple's developer site for more info.
--Mike
You should definitely have a look at UIPasteboard, as suggested – you can create a new pasteboard for use by the applications you are creating (though nothing will stop other apps using them, but people are faily unlikely to). A UIPasteboard is persistent through a power cycle / reboot – it will exist until the creating application is deleted.
You could also have a look at the SwapKit libary (which looks very cool):
http://infinite-labs.net/swapkit/