The final test

During the early days of iPhone software development, there were no mechanisms for doing beta tests. Those of us on the bleeding edge were developing apps with very little peer review and beta testing.

Luckily, I have friends who are a lot smarter than me. And we banded together with one primary rule: you don’t talk about Fight Club. Despite the NDA, we were determined to test each others applications.

This was accomplished by distributing unsigned applications amongst the group. Each member of the group then signed the app with their own developer certificate and installed it with Xcode. We all got pretty good with the codesign utility because it was so exciting to see each others work.

But this essay isn’t about reminiscing. It’s about telling you how to test the applications you upload to iTunes Connect.

If you’ve submitted an application to the App Store, you know that sinking feeling of not being able to test your final build. The binary that gets signed with the “App Store” distribution mechanism cannot be run on your test devices: you can’t be sure that the final bits you send to Apple are complete.

But there’s a simple way around this problem and it’s called codesign. The same application we used for our pre-Ad Hoc beta testing can also be used for a final test on your App Store submissions.

The first step is to create your distribution build for the App Store. For this example, we’ll be using the Frenzic application and putting it into build/Distribution-iphoneos. After the build completes, make the ZIP file archive immediately. Put it in a safe place so you can upload it to iTunes Connect after you finish your final test.

Now verify that you’re dealing with the right application. Go to the build folder and issue the following command:

$ cd build/Distribution-iphoneos
$ codesign -d -vv Frenzic.app/Frenzic

You’ll then see a verbose dump of the signature in the application:

Executable=/Users/craig/Projects/FrenzicTouch/build/Distribution-iphoneos/Frenzic.app/Frenzic
Identifier=com.iconfactory.Frenzic
Format=bundle with Mach-O thin (armv6)
...
Signature size=4331
Authority=iPhone Distribution: The Iconfactory
Authority=Apple Worldwide Developer Relations Certification Authority
Authority=Apple Root CA
Signed Time=Nov 12, 2008 1:46:07 PM
...

The most important part of that output are the lines beginning with “Authority”. It shows that the “iPhone Distribution” certificate for The Iconfactory is being used. This is what Apple needs, but it’s also the thing that keeping you from running the app on your test devices.

So let’s change it.

The first thing you need to do is define an environment variable that gets the correct version of codesign_allocate (the one in /usr/bin doesn’t currently support ARM):

$ export CODESIGN_ALLOCATE=/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/codesign_allocate

If you forget to do this, you’ll see this error message when you try to sign the binary:

codesign_allocate: unknown architecture specification flag: -a armv6 6720

Now you can sign the application using your own certificate:

$ codesign -f -s "iPhone Developer" -vv Frenzic.app/Frenzic

The -s parameter should be the same value as the Code Signing Identity > Any iPhone OS Device setting in your Xcode project. The -f parameter tells codesign to force the replacement of the signature. As the command executes, you’ll see the following output as the signature is replaced:

Frenzic.app/Frenzic: replacing existing signature
Frenzic.app/Frenzic: signed bundle with Mach-O thin (armv6) [com.iconfactory.Frenzic]

After you’ve re-signed the app, you’ll see that I am now the authority. But you probably already knew that:

$ codesign -d -vv Frenzic.app/Frenzic Executable=/Users/craig/Projects/FrenzicTouch/build/Distribution-iphoneos/Frenzic.app/Frenzic
Identifier=com.iconfactory.Frenzic
Format=bundle with Mach-O thin (armv6)
...
Signature size=4302
Authority=iPhone Developer: Craig Hockenberry
Authority=Apple Worldwide Developer Relations Certification Authority
Authority=Apple Root CA
Signed Time=Nov 12, 2008 6:35:06 PM
...

Now you can move the updated application onto a test device and make sure that the final build is OK. Everything except the signature is the same: if there’s a missing file or something that’s messed up, you’ll be able to find it before the QA engineers at Apple do (and with 10 day turnaround times, that’s a very good thing.)

Once you’re happy that everything looks good, upload the ZIP file you created earlier to iTunes Connect and crack open a beer. As you’re enjoying that beer, take a look at the codesign man page for more information on this essential utility. Or write an essay for your web log :-)

Updated July 2nd, 2009: Note that this procedure can also be used if you are beta testing. This is particularly helpful in cases where you’ve upgraded to an iPhone 3GS and the Ad Hoc .mobileprovision file for the beta contains the UDID for your older device. Many developers have hit the 100 device limit since the release of the new phone, and can’t add devices into a new .mobileprovision file. You’ll be able to test the beta releases after signing the code with your own certificate. The only case where this won’t work is when the app being resigned uses the keychain.