Index Page last updated on December 17, 2008 at 6:20pm EST

Good Practices: iPhone Development

Note: This page was published in December of 2008. Xcode has changed a lot since then, so take everything that follows with a grain of salt.

I suppose these are usually called “best practices”, but who am I to say what’s best?

I write iPhone applications for hire. Usually, this means managing multiple clients' code signing certificates and keys on one computer. Here are some tips I figured out the hard way:

Name your keys as soon as you generate them

This is first on the list because, if you don’t do this, you will have to resort to brushing up on public key cryptography and openssl arcana in order to determine which public key goes with which certificate.

Each time you use Keychain Access to create a Certificate Signing Request, it generates a public and private key, each named with the certificate’s common name. Do this twice (say, to obtain both a Developer and a Distribution certificate), and you’ll have four keys with the same name and no idea which public key goes with which private key. Rename the keys immediately after you generate a C.S.R. and save yourself some trouble.

Create a separate keychain for each client

In Keychain Access you can create separate keychains, which are groupings of passwords, certificates, keys, and secure notes. At a minimum, it should contain your client’s iPhone Distribution certificate and private key. It’s a useful place to store related passwords and other sensitive information (e.g., to the client’s web host account).

The latest release of Xcode will only search your default keychain, which makes following this advice somewhat annoying. To get around it, I keep my iPhone Developer certificate in my login keychain, then use the security command line utility to change and restore the default keychain setting in my distribution build scripts.

Use your own iPhone Developer certificate for every project

The default Xcode project template is configured to sign your code using any certificate starting with “iPhone Developer”; if you have more than one iPhone Developer certificate installed, the build will fail because Xcode doesn’t know which one to use.

You could solve this in five seconds by explicitly selecting your certificate in your project’s build settings, but then everybody else who opens the project file will have to change it back. It’s better to leave the project alone and make sure that you only have one iPhone Developer certificate installed.

For this to work correctly, you must also configure your Developer Provisioning Profile with an absolute wildcard App ID (e.g., “*”) so that it will allow you to sign any app regardless of its bundle identifier (because each client is going to have a completely different bundle identifier).

Note that I’m talking about Developer certificates (what you use for debugging your app), not Distribution certificates (what you use for creating Ad Hoc and App Store builds). Use your own Developer certificate for all of your work and use the client’s Distribution certificate for each project.

Set up three Xcode project configurations: Debug, AdHoc, and AppStore

If you’ve set up your iPhone Developer certificate and provisioning profile correctly, you won’t have to make any changes to the default Debug configuration. Duplicate the default “Release” configuration, then rename one “AdHoc” and the other “AppStore”. Then edit the AdHoc configuration so you can send alpha and beta builds to your client and the AppStore configuration for submitting to the App Store.

Don’t use the default bundle identifier

If you do, you might run into problems. The default value (in the Info.plist file) is “com.yourcompany.${PRODUCT_NAME:identifier}”, which magically creates an identifier out of the PRODUCT_NAME build setting. Cute, but causes more trouble than it saves for a value that should never change. All that “:identifier” suffix does is transform it into a valid XML identifier, but that’s not good enough for an App ID. If your app name contains certain characters, like an apostrophe, that incantation will translate it to an underscore. Unfortunately, your bundle identifier is a Uniform Type Identifier (UTI), which does not permit underscores, and you won’t be informed of the problem until after you upload your app to iTunes Connect.

Note that although hyphens are allowed in UTIs, the Program Portal will not allow you to generate an App ID containing one. It will, however, allow you to create an App ID containing an underscore, which makes it an invalid UTI… so you’re better off avoiding hyphens and underscores entirely.

Set the bundle identifier based on build configuration

If two app bundles have the same bundle identifier, then iPhone OS considers them to be the same application. Thus, if your Ad Hoc beta builds use the same identifier as your App Store production builds, you cannot have both installed on your phone simultaneously. Give your betas a different identifier, and your beta testers won’t have to delete and reinstall the “real” version before and after testing.

To do this, create a User-Defined Build Setting in Xcode, such as BUNDLE_IDENTIFIER. In your AppStore configuration, give it a value like “com.yourcompany.MyGreatApp”; in your AdHoc configuration, give it a value like “com.yourcompany.MyGreatApp.beta”; in your Debug configuration, set the value to “com.yourcompany.MyGreatApp.debug”. Then use the value in your Info.plist file by setting the bundle identifier to “${BUNDLE_IDENTIFIER}”.

I also recommend using the same trick for the Info.plist bundle display name property, appending “∂” (Greek letter delta, type option-d) or “β” (Greek letter beta, use the character palette) to the Debug and AdHoc builds respectively.

I have noticed that sometimes the Xcode debugger launches mistakenly the AdHoc version of an app if it is installed on a device alongside a debug version. I haven’t tried it, but changing the app’s file name (via the WRAPPER_NAME build setting) might solve that problem.

Automate your Ad Hoc and App Store build process

You want a script so that, with one command, you can build your application and produce zip files suitable for sending to beta testers and/or uploading to the App Store. Automating the process will make it much easier to send frequent beta releases to your clients (they will be happier) and you will have full faith that the zip file you are sending to Apple is virtually identical to the ad hoc build you just tested, even at 3 o'clock in the morning.

Here’s what a good build script should do:

  1. Perform a clean checkout from your source control system.
  2. Build your app using the AdHoc configuration and create a zip file.
  3. Build your app using the AppStore configuration and create a zip file.
  4. Name those zip files with a time stamp or build number.
I wrote an Ant script which tags the repository with a name like “build-0027”, exports it to a RAM disk, then calls xcodebuild to do the work from there. Once it is done I can easily send the AdHoc zip file to my client for testing. If we decide to ship it, I have a complementary AppStore version ready to submit to Apple. And I don’t have to worry about differences between the version I tested and the version I submit.

If you write your own build script, note that an archive created with the “zip” command may not be accepted. I think the problem has to do with symbolic links in the archive. I use “ditto” to create my archive; I’ve also heard of success using “zip -y”.