Monday, February 20, 2012

Automating the management of iOS provisioning profiles with Jenkins

Manupulating iOS provisioning profiles is a bothersome process. Once you have added a device to a provisioning profile, you need to distribute it to your team, add it to the XCode Organizer, and register it in your XCode project sign configuration. Most of this can be now be completely automated.


At We Want To Know, we use Jenkins to automate the build of our Unity3d projects. I will make a detailed post about our setup later on.

In our build pipeline, Unity3d generates an XCode project that is then built and deployed to testflight. In order for our testers to get access to our build, we sometimes need to update the provisioning profile, both on the build machine and in the xcode project configuration.

The main issues we were facing were that

  • we didn't want to do this manually on our machine nor on the CI server

  • the xcode project file isn't stored in our SCM (remember it was generated by unity)



In order to overcome these limitations, I've implemented various scripts to automate the management of the iOS provisioning profiles, on the command line and with jenkins.

We now use

  • first a job to download information automatically (once per day, but can be triggered manually) and saves the information offline in a zip file. This zip file contains our development and distribution provisioning profiles and a JSON representation of the Apple Provisioning profile center data: the list of provisionning profiles and the list of devices

  • second, as part of our iOS Unity3d builds, a new build step is added before the Unity build step to automatically (if needed)

        install the new provisioning profile in the xcode organizer space

        update the XCode project configuration to use the new provisioning profile




As a consequence, if you update the provisioning profile information on the Apple Developer Center (you still have to do that manualy), all you (or someone from your team) have to do is to (optionally) trigger the offline apple developer center data update job and trigger your normal build. The next testflght deployment will automatically reflect the new provisioning profile.

We have one less thing to maintain on the box. Those scripts are also usable on the developer desktops.

We can now make a build remotely and distribute it automatically to our newly registered tester without access to a developer station.

More details


The apple developer center offline job



This is taken care by a simple free-style job. To improve security, I've first configured it with the build secrets plugin, in which I've linked to the APPLE_DEV_CENTER_CONFIG environment variable an uploaded file containing the encrypted login information for our Apple developer site.

The second element, the core of the job, is a shell script job containing:

ls -lR $APPLE_DEV_CENTER_CONFIG
mkdir -p adc
rm -f adc/*
ruby ./apple_dev_center.rb -C $APPLE_DEV_CENTER_CONFIG/our_apple_dev_center.config -S "our seed" -u ourappleidemail@example.com -d adc -O adc/site.json
zip -r adc.zip adc/


The update of the provisioning profiles in the Organizer and in the XCode project


Here we added a shell script job before our unity3d build. That script does the following

echo "Updating xcode project file and provisioning profiles"
ADC_DIR=${WORKSPACE}/../../infra_apple_developper_site/workspace/adc/
SITE_JSON=${ADC_DIR}/site.json
xcode_project_file=${WORKSPACE}/target/dragonbox_ios/Unity-iPhone.xcodeproj/project.pbxproj
configuration="Ad Hoc"
profile_type="distribution"
profile_name="YOUR PROFILE NAME"

cd ${WORKSPACE}/../../infra_apple_developper_site/workspace/xcode/
./xcode_update_pp.sh "${ADC_DIR}" "${SITE_JSON}" "${xcode_project_file}" "${configuration}" "${profile_type}" "${profile_name}"


As you can see this is still pretty ugly, because of the relative, but it works very well. I hope to clean this further in the future. Maybe by moving part of the configuration into the unity3d project.

The output of the script in the console looks like this:


[...]
+ ./xcode_update_pp.sh /Users/Shared/Jenkins/Home/jobs/game_DraggonEggs-trunk_iOS/workspace/../../infra_apple_developper_site/workspace/adc/ /Users/Shared/Jenkins/Home/jobs/game_DraggonEggs-trunk_iOS/workspace/../../infra_apple_developper_site/workspace/adc//site.json /Users/Shared/Jenkins/Home/jobs/game_DraggonEggs-trunk_iOS/workspace/target/dragonbox_ios/Unity-iPhone.xcodeproj/project.pbxproj 'Ad Hoc' distribution 'YOUR PROFILE NAME'
INFO profile /Users/Shared/Jenkins/Home//Library/MobileDevice/Provisioning Profiles/9274AB2A-6F96-4BFF-B320--------------.mobileprovision not yet installed. Installing...
INFO Replacing D54B7721-4164-444C-8851-------------- with 9274AB2A-6F96-4BFF-B320-------------- in /Users/Shared/Jenkins/Home/jobs/game_DraggonEggs-trunk_iOS/workspace/target/dragonbox_ios/Unity-iPhone.xcodeproj/project.pbxproj
--- /Users/Shared/Jenkins/Home/jobs/game_DraggonEggs-trunk_iOS/workspace/target/dragonbox_ios/Unity-iPhone.xcodeproj/project.pbxproj 2012-02-19 19:57:26.000000000 +0100
+++ /Users/Shared/Jenkins/Home/jobs/game_DraggonEggs-trunk_iOS/workspace/target/dragonbox_ios/Unity-iPhone.xcodeproj/project.pbxproj.new 2012-02-20 20:39:31.000000000 +0100
@@ -605,7 +605,7 @@
GCC_WARN_UNUSED_VARIABLE = YES;
OTHER_LDFLAGS = "-Wl,-S,-x";
PREBINDING = NO;
- "PROVISIONING_PROFILE[sdk=iphoneos*]" = "D54B7721-4164-444C-8851--------------";
+ "PROVISIONING_PROFILE[sdk=iphoneos*]" = "9274AB2A-6F96-4BFF-B320--------------";
SDKROOT = iphoneos4.2;
};
name = "Ad Hoc";
[...]


Show me the money!


The code for these projects is stored online on https://github.com/lacostej/iOSprovisioningprofiles with a few READMEs that should help you getting started.

Feel free to provide feedback and pull requests!

6 comments: