If you’re into any sort of iOS development, you’re likely spending a lot of time with .ipa files, code signing entitlements, provisioning profiles, and development certificates. If your experience has been anything like ours, some days the code signing process has been nothing but a big headache (judging by the grumbling we see on Twitter from time to time, we know this has to be true for others out there, too). Sometimes it seems like simply updating a provisioning profile takes way longer than it should as you wade through the cryptic error messages Xcode gives about code signatures and entitlements. When deadlines loom, anything that gets between you and your final deliverable is just unneeded stress. We want to share with you a snippet of a shortcut in our workflow that has helped us save time when updating a provisioning profile or diagnosing invalid entitlements errors and the like. Before we get to that, we thought it would be helpful to get us all on the same page about provisioning profiles and code signatures.
The Structure of an iOS App
If you aren’t very familiar with iOS development, Mac packages or that sort of file in general, you may not be aware that the .ipa file that gets generated from Xcode is actually just a zip file that contains your app and the iTunes information (e.g. iTunesArtwork) that iTunes uses to manage the app. You can unzip this file by changing the extension to .zip or opening Terminal and running
unzip app.ipa -d app/
This will unzip the contents of the ipa file to the “app” directory. Within this directory, you’ll find this structure:
The .app file within the Payload directory is actually a folder with a file extension. You can open this by alternate clicking and selecting “Show Package Contents.” Within this file are all the resources for your application (images, HTML, video, etc.) and the compiled binary of your app. Also within this file is a file named embedded.mobileprovision. This is the provisioning profile that was originally packaged with the application. iOS automatically installs this provisioning profile on the device when installing the application (if the provisioning profile doesn’t already exist on the device). The provisioning profile is a plist file that specifies a handful of permissions for your app–most notably, the devices that it is provisioned to run on (for development or ad-hoc releases). If you’re running into an issue where an app is not installing on a device, you can verify whether the UDID is included in the embedded provisioning profile by opening the file in a text editor and finding the ProvisionedDevices key.
The last component of the .app file is the code signature contained within the _CodeSignature folder. The purpose of the code signature is to verify that every byte within the .app file is exactly the same as when it was signed by it’s creator (specified by the signing identity). Even swapping out an image with another image (even if it has the same name) will invalidate the signature. Any changes made to the .app file requires that the whole package be re-signed.
The Entitlements File
The entitlements file is used during code signing to specify special permissions within your app (like access to a shared keychain). Most apps use it to disable the
get-task-allow property with specifies whether other users may debug your application (e.g. using Instruments). The entitlements file doesn’t actually belong inside the .app file (it shouldn’t be part of your Copy Bundle Resources build phase in Xcode), it is only used during the code signing process. You don’t need the entitlements file for a development build using a development provisioning profile unless you want to use push notifications, iCloud storage, or keychain sharing–to enable these features you must specify an entitlements file during code signing. Don’t forget that your entitlements file must also contain the
application-identifier key (e.g. 123456789.com.floatlearning.app).
Re-signing an Application
You may ask why you would ever want to modify the .ipa outside of Xcode. There are a few reasons we’ve wanted to do it: first, to update a mobileprovision file. Occasionally we’ll want to add a UDID to the provisioning profile for the app. We can simply swap out the embedded.mobileprovision file instead of needing to go through Xcode and rebuild the app. Also, from time to time, we’ll run into an issue where a client may get an error “The executable was signed with invalid entitlements.” This is the result of a mistake made earlier in the development process (e.g. forgetting to update the
application-identifier within the entitlements file after changing the bundle identifier), but it is easily fixable without needing to rebuild the entire app. You could even make updates to the Info.plist file (e.g. changing the bundle identifier) if you really wanted to.
When you installed the Xcode developer tools, it included with it an application called
codesign (/usr/bin/codesign). This is the application used by Xcode and the Xcode Organizer to sign your app after it has been built. We can use this application to replace an existing code signature after changing bundle resources or wanting to modify the entitlements that were used during code signing. You can use
man codesign to get a description of all the possible arguments available to you, but we’ll call out the two we care about:
|-f||This flag allows us to “force” a code signature replacing the existing one. If we don’t specify -f, the code signing process will exit if a code signature already exists.|
|–entitlements=path||This flag specifies the entitlements file to use for the code signature.|
Our Signing Shortcut Script
When updating a provisioning profile or the entitlements of an already compiled app, we found ourselves repeating the same steps over and over again: unzipping the file, replacing the embedded.mobileprovision file, resigning the .app file, and packaging back up the .ipa. It wasn’t saving any time over simply going through Xcode–so we wrote a small bash script that does all the nitty-gritty work for us and we’d like to share it with you:
This script will take a signed or unsigned app (either .ipa or .app), sign it, and package it up into a new .ipa file.
./floatsign source identity -p "path/to/profile" -e "path/to/entitlements" target
|source||The .ipa or .app file that needs signing.|
|identity||The name of the code signing identity to use (e.g. iPhone Developer: Daniel Pfeiffer (ABC1234567)).
This is your development/distribution certificate provided by Apple. You can find out the common name of this certificate by looking in Keychain Access (we find it helpful to filter the list by clicking on “My Certificates” in the left column).
|target||The target for the newly-signed .ipa file.|
This likely won’t cover every possible requirement in signing an iOS application, but it has been very helpful in our development process and we hope you find it to be helpful too. If you make any improvements to the script, please let us know in the comments or by making a Pull request on Github!
If you’re not the Terminal type, Brian Gorby (http://www.gorbster.net/) has created a droplet app for Mac, AppResigner, that does the same thing (but just with .app files; you’ll have to do the unzipping and zipping yourself if you only have a .ipa file).
Interested in learning more about mobile development? Maybe your organization is looking to create its first mobile learning application?
Contact us to learn more!