Dan’s Dev Diary didn’t work out like I thought. I didn’t post much and I’m saddened by that. I’m going to leave this up as long as tumblr sees fit to host it. I have imported all of these posts over to my personal blog. All future posts will occur there.
Further adventures in resigning for iOS
In the beginning days of iOS development, before the official SDK release, Craig Hockenberry (@chockenberry) helped everyone out by figuring out app resigning. He has the seminal post on app resigning. I learned what I needed from it. Craig is the giant on whose shoulders I’ve stood.
I work at a large iOS game studio. Due to restrictions and device limits on the Apple Dev Portal we have to create many versions of each build that is generated so that we can make sure it can run on any device we have. As I have developed a custom resigning system I’ve learned a few things that help in addition to Craig’s post.
First, every iOS app bundle has the profile it was signed with when built in Xcode embedded in it. This causes no end of issues with resigning because you can’t just drop the freshly resigned app bundle onto a device unless you first have the resigned profile already installed. Why is that? If you ever watch the steps of app install you’ll see at some point it copies the embedded profile from the app bundle to the device. After that it does the codesign comparison to see if the executable is allowed to run on the device (which is why when you install an app with invalid permissions it copies the whole thing to the device and then errors out telling you there are not sufficient permissions). When you have an app bundle that contains an embedded profile that matches its signing everything is copacetic will install smoothy, assuming the device is on the provisioning profile.
At my day-job we combatted this problem by educating users to always install the provisioning profile and app bundle at the same time, they are distributed together for just this reason. This of course leads to problems down the road when a device has multiple copies of a profile and one expires, but that’s a story for another day. Not being able to allow users to just install an app bundle without a provisioning profile on resigned builds didn’t make much sense to me, especially in light of buiding IPA bundles for over the air distribution, so I dug in a bit more. It turns out there’s a solution staring you right in the face in your Xcode build logs.
Remember how I said there’s an embedded profile for each app bundle? Well, you just need to copy your resigning provisioning profile into the app bundle:
% cd $SRCROOT/build/Debug-iphoneos % cp AltDevPortal.mobileprovision SomeApp.app/embedded.mobileprovision
Okay, now you’ve got that in the app bundle you need to tell codesign about it:
% export EMBEDDED_PROFILE_NAME=embedded.mobileprovision
And, using Master Hockenberry’s steps from his post we get this as the entire set of steps to successfully resign an iOS app bundle:
% cd $SRCROOT/build/Debug-iphoneos % cp AltDevPortal.mobileprovision SomeApp.app/embedded.mobileprovision % export EMBEDDED_PROFILE_NAME=embedded.mobileprovision % export CODESIGN_ALLOCATE=/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/codesign_allocate % codesign -f -vv -s "iPhone Developer" SomeApp.app
Do note that if you’re working like me and you have more than one portal at your command and far more than a handful of profiles (say over 100) then you’ll want to be more explicit with the codesign tool. I use the command like so:
% codesign -f -vv -s "iPhone Developer: Build User (XXXXXXXX)" -i <profile name> SomeApp.app
The profile name used is generally the UUID of the profile. If you look in ~/Library/MobileDevice/Provisioning\ Profiles you’ll see the files are moved to the UUID name when installed by Xcode. You can manually copy a file in there, say SomeApp.mobileprovision, and then use -i SomeApp in your call to codesign.
"Base SDK Missing", hateful words for not much longer
In a hypothetical future version of developer tools from a well known fruit-based technology company there might never need to be a reason to edit your project or target settings to pick the new SDK that you’ve just installed (for if you don’t you certainly won’t be able to build your project).
In getting ready for that change when it’s potentially released I was experimenting with the settings on the current 4.1 SDK. It turns out that while there’s not a nice GUI selector and the Xcode interface will still complain that the project has the “Base SDK Missing,” you can still compile and your project will pick up the highest numbered SDK available (which may or may not be the way this hypothetical future release will work).
"But Dan, how do you do this today?" you ask? Good question, let me show you.
In your project settings (or target settings, but I’d recommend project-level settings and then let your targets inherit that setting) you goto the selection for Base SDK:
In this case your project was from iOS 4.0 and now you’re running on 4.1. In it’s current state it won’t compile. The simple fix for this is so that you’ll never have to update that setting again is to select the “Other…” option at the bottom:
And when the dialog sheet drops down just remove the SDK version numbers:
When you’re done the Xcode UI will still say the dreaded “Base SDK Missing”:
But running a build will work. The good news is that this works on the xcodebuild command line too. Just pass the -sdk flag “iphoneos” (or “iphonesimulator”) and it will pick up the latest version of the SDK you have installed. Hopefully that hypothetical future version of the tool set will provide better UI support for this, until then have fun not worrying about your Base SDK again.