For at least a year now I haven’t had any struggles with Xcode’s code signing, thanks to the following habits. Some of them seem like overkill, and all of them are a lot “harder” than using the built-in “support” in Xcode, but — fuck all that noise. Do these things1 and get back to work:
Never use Xcode’s built-in code signing helpers. Especially avoid any button that says Fix Issue. It fills your Developer portal with dozens of worthless “iOS Team Provisioning Profile Blah…” profiles and leads you towards Provisioning Profile Rot.
Never use wildcard app identifiers. These are especially problematic when you belong to multiple teams, each with multiple wildcard app identifiers. Take the extra few seconds it takes to log into the developer portal on the web and create an app-specific bundle ID for every app, even proofs-of-concept. By avoiding wildcard app identifiers you eliminate an entire vector of shit on the path to code signing hell. If you have any existing wildcard profiles, delete them all immediately. Modern versions of Xcode make this much harder to do than it used to be. Let me Google that for you. If you really need a wildcard app identifier, just create an identifer that is literally
com.company.RadarSample, etc.) and re-use it as needed.
Use build configs and shared schemes. Make life easier on yourself and check the “Shared” box in the “Manage Schemes…” window next to at least two schemes. Have one for development and one for App Store releases at the very least. Consider adding a third for beta builds if necessary. Select the appropriate build config in the editing window for each scheme. If you use the default build configs provided by Xcode that’ll be
Debugfor your development scheme and
Releasefor your release scheme.
Use explicit code-signing identities, and automatic profile selection. Since you’re now using shared schemes linked to specific build configs, you can make your Xcode project settings even more helpful. In the Code Signing Identity and Provisioning Profile sections for your project settings, specify explicit signing identities for any build configs that require distribution certificates (Ad Hoc, Enterprise, or App Store distributions). You can also try the automatic
iOS Distributionsetting if you’re lazy, but I’m on too many teams and don’t trust Xcode to do the right thing. I do recommend using the
iOS Developerautomatic setting for your
Debugbuild configs, since this scales better when working with other developers. I have found that by using the above settings for signing identities, I can use the
Automaticprovisioning profile setting for all build configs without hiccups.
Repeat your project-level settings at the target level. Another common problem is when project-level settings for code signing and profile selection don’t match the target-level settings. Unless you think you’ll never make this mistake (I used to think I could handle this. Now I know better.), manually set the code signing and provisioning profile settings at both project and target levels. Periodically check them to make sure they didn’t get out-of-sync.
Delete expired certificates from Keychain Access. Keychain Access makes this pretty easy to do. Most certificates (Ad Hoc, APN, and App Store) expire after 365 days. Some Enterprise certificates may last up to three years. Create calendar alerts the same day you create new distribution and APN certificates, to remind yourself to get them updated and ready to go ahead of time, before they expire and your APN server starts flaring up with signing errors.
Make sure you have all the certificates you need in Keychain Access. You will need at least two certificates for each team to which you belong: 1) A developer certificate that gives you permission to install apps on your own devices. 2) A distribution certificate that allows you to sign Ad Hoc and App Store builds. You might also need two additional certificates for push notifications (one for development and one for production builds). Developer and Distribution certificates apply to all apps on your team. APN certificates are specific to each application. Expand the carets to ensure that you also have the private keys for all these certificates. Store your certificate exports someplace that is both secure and convenient. Everyone on your team should be able to ship to the App Store in case all your senior engineers get serial-crushed by some huge friggin guy.
Relaunch Xcode whenever you install new profiles or certificates. Cached expired certificates are particularly prone to caching errors.
Update 1: I’ve posted a follow-up article with code sigining tips for Apple Watch apps. April 25, 2015 — JTS.
Update 2: If you use CocoaPods, you’ll need this post-install script to make sure all your dependency frameworks are using the correct code-signing identities for the current scheme/config. My script assumes that you are using a distribution identity for configs named
Caveat: I only stand by this advice for iOS projects. I’ve no idea what kind of cowboy antics you’d have to do when shipping OS X binaries for both Mac App Store and direct sales distribution. ↩