I wanted to share my experience with both tools, but first let's start with some assumptions and requirements:
- As of today the most updated development environment version is XCode 4.5 w/ iOS 6.0. It is highly recommended to update to the latest and greatest version so things work properly.
- I used the latest Jenkins which is downloadable from its download site
- After installing Jenkins, I used this cool xcode-plugin that really helps to get things done. You can install it by going to Manage Jenkins | Manage Plugins | Available | Search for xcode and install it.
- As an optional step you should also install the Amazon S3 plugin to push the "Enterprise Site" artifacts (the IPA and PLIST files) so it can be available to others in your team.
- You must have Apple's iOS Developer Program account. Make sure you create a Certificate and Distribution (Adhoc) provisioning profile using the portal. Start by creating a certificate for Distribution (remember to do this through the "Distribution" tab) and continue with adding the devices you want to test with. Finally create a provisioning profile (remember to do this in the "Distribution" tab). If you have done things correctly you should have a certificate in your default keychain. Here is what I see:
(1) Apple's Certificate (2) Your Certificate (3) Your private key
Make sure you have something like this in your user's Keychain
- Another assumption is that you use the latest version of Phonegap (currently v2.2) which provides handy command line tools to create iOS application shell. I used:
./path/to/cordova-ios/bin/create /path/to/my_project com.example.my_project
Now before we start the real fun, let's explain a couple of caveats for working with Jenkins in this context:
- Jenkins jobs run as the jenkins user (created by the Jenkins installer), your jenkins user doesn't really know about the Keychain that you have created. We will create a different Keychain accessible by your jenkins user.
- Same goes to provisioning profiles, we will need to install the distribution provisioning profile for the jenkins user.
- Code Signing for development and distribution is done with different provisioning profiles, from time to time, developers override the project settings so the profile (the Xcode UI really sucks!) is configured wrongly. For this end we will add a script that makes sure we use the right profile.
Now let's start the real fun:
- Export the user's Keychain (usually under /Users/
/Library/Keychains) and import it into new Jenkins' Keychain (usually under /Users/Shared/Jenkins/Library/Keychains):
user$ security default-keychain # retrieve the user's default keychain
user$ security export -k <user-keychain> -f pkcs12 -o <output-file-name>
user$ sudo su jenkins # switch to jenkins account
jenkins$ security create-keychain -P <jenkins-keychain>
jenkins$ security import <exported-file-name> -k <jenkins-keychain> -f pkcs12 -A
jenkins$ security default-keychain -s <jenkins-keychain>
- Copy your distribution provisioning profile to jenkins' user profiles directory /Users/Shared/Jenkins/Library/MobileDevice/Provisioning Profiles/
- Create a Jenkins job using the xcode plugin
Fetch your code from git then add a build step which executes the xcode plugin build
Remember that you should fill in these parameters
- Project directory
- output directory
- Build IPA
- Provisioning profile - direct to your profile
- Unlock the keychain and provide the Keychain and its password
- In your job you will need to make sure that the right profile is used during the execution, I had to use some search and replace tricks. For this end I first find the provisioning profile's hash (a 28 hex-decimal hash):
cp </path/to/.xcodeproj>/project.pbxproj </path/to/.xcodeproj>/project.pbxproj.bak
sed 's/PROVISIONING_PROFILE\ =\ "[^\"]*"/PROVISIONING_PROFILE\ =\ "<Profile Hash>"/g' </path/to/.xcodeproj>/project.pbxproj > </path/to/.xcodeproj>/project.pbxproj.pro1
sed 's/\"PROVISIONING_PROFILE\[sdk=iphoneos\*]\"\ =\ "[^\"]*"/\"PROVISIONING_PROFILE\[sdk=iphoneos\*]\"\ =\ "<Profile Hash>"/g' </path/to/.xcodeproj>/project.pbxproj.pro1 > </path/to/.xcodeproj>/project.pbxproj.pro2
mv </path/to/.xcodeproj>/project.pbxproj.pro2 </path/to/.xcodeproj>/project.pbxproj
- Distribute to external enterprise site - this one worth a separate post