iOS Ad-Hoc Beta publishing directly from Xcode

A couple of weeks ago I posted about automating Ad-Hoc publishing using some simple shell scripting and a modified version of the BetaBuilder utility by Hunter Hillegas. Based on a comment on his blog I’ve taken this a step further: I’ve fully integrated the publishing mechanism into Xcode. Here’s how…

Aggregate Targets

First step, if you don’t have one already, create a build configuration called something like “Ad Hoc” to differentiate a build from the normal Release and Debug variants. This is easily done: Go to the Project menu → Edit Project Settings (or, right-click or control-click on the project name at the top of Groups & Files or you can even double-click on the icon to open this). Go to the Configurations tab and “Duplicate” the Release configuration. I call this copy “Ad Hoc“. Then you can change the code signing identity of this new configuration to the Ad Hoc profile you generate on the Apple Provisioning Portal. Remember in future that if you change any settings in the Release configuration, you may also need to change them in the Ad Hoc one too. Note: Does it need to be called Ad Hoc?»

Xcode Aggregate Targets

Xcode Aggregate Targets

At first thought the approach to use to automate distribution appeared to be adding a build step at the end of the target configuration in Xcode – however this has a problem: Codesigning occurs after any configurable build steps and we need to be able to use the signed version of the package. No problem! Xcode has an aggregate target type for just this situation – a Shell Script Target whose description reads “Target that just executes a script rather than building a product”. Better yet, aggregate targets are designed to be dependent on other targets so that they get executed after they have been built. This is exactly what we need. You add a target by right-clicking (control-click) on Targets in Groups & Files, choosing Add → New Target… and in the Mac OS X → Other section there’s a selection of aggregate targets. I name this target “Package & Distribute Ad Hoc” but you can call it whatever you want.

Example Shell Script Target

Example Shell Script Target

You now have a new target in Groups & Files. If you expand it you will see it has a single build step named “Run Script“.

You should right-click on this, select Get Info and you will then be presented with a dialog box with a basic “Script” text entry field.

What I use here looks like this:

Shell Script Configuration

Shell Script Configuration

Quite simply, ipa-packager is a shell script based on the one in a previous blog post that does the packaging for me. If it returns an error code, so do we – this is the signal to Xcode to stop the build process. All the other options to the Run Script dialog we leave at defaults.

Lastly, we need to make this new target depend on the target of our app. The easiest mechanism to do this is to simply drag-and-drop the app target, under Groups & Files, into the new target. Job done.

Packaging revisited

So, what next? If we try to build the project above it will complain because ipa-packager doesn’t exist. I reworked the script from my previous blog post to work either directly from the command line or using the environment variables that Xcode passes to scripts. The revised version appears below and is attached at the bottom, for download.

I also improved a number of items, particularly dependency checking so it does not re-do work that is unnecessary. Another area I paid attention to is being able to provide some of the settings in either the Xcode project or target build configuration – any user-defined values are also provided in the environment of the script. This is just as well since, because the script is called from its own target, the environment variable identifying the current target is that of the script, not our iOS app! Consequently, I have to provide at least one setting in the project: ADHOC_TARGET_NAME which I set to the name of the app.

One more major improvement is the provision of a local “configuration” file that allows a user of this script to set their own defaults without having to tweak the script itself. An example is given below. I will at some point add a command line tweak to allow for an arbitrary file to be used for this configuration.

Shell script: ipa-packager»
Configuration file: ~/.adhoc-distribution.conf»

Naturally you will wish to alter the publishing URL to one that works for you or, as described in the next section, you can do this in the project configuration inside Xcode.

The observant reader will have noticed references to an ADHOC_TEMPLATE_HTML value. This is not yet used but it will allow a project to provide its own HTML template for the generated index.html file, the same way it does now for the README.txt file.

Configuring from Xcode

So, we have our Xcode target and we have the script that does the magic of packaging and distributing an Ad Hoc build. There’s one component left – the values that we need to pass from Xcode to ipa-packager. There’s more than one place you can do this (project or target level), and you can apply it to just Ad Hoc builds or to all – even though it won’t distribute code for non Ad Hoc builds, you may wish to archive development and release builds all the same. You should decide what functionality you want and where to keep the values. The suggested approach is to keep values unique to a target within that targets configuration and is what I shall demonstrate here.

Xcode Target Build Configuration

Xcode Target Build Configuration

We need the Target Info page open for the aggregate “Run Shell Script” target we added earlier (right-click, control-click or double-click on the target under Groups & Files) and select the Build tab. The item “Configuration:” is where you will decide whether to apply the values to one specific configuration (such as Ad Hoc) or to all of them. Then quit simply use the cog-menu at bottom-left to Add User-Defined Setting. There is only value you must specify as barest minimum: ADHOC_TARGET_NAME which needs to refer to the name of the target in the project that contains your app. This should also be the same as the application name – that is, the name of the .app package.

You can also specify any of the values used by ipa-packager though note that the results may be undefined if you try to redefine a value provided by Xcode itself. Where I use a common URL scheme for all my projects, others may wish to specify a unique URL for each project and you can do that here by adding a value for ADHOC_PUBLISHING_URL to their project. See the script for the full list of values it will look for.

Replaceable values

Some of the environment variables that ipa-packager uses have a notion of replaceable values. These are components of a string that are replaced with values that are determined at runtime. The idea is to enable these variables to provide a template for the final value. For example, the default for ADHOC_PUBLISHING_URL is http://localhost/iosbeta/#SHORTBUNDLEID#-#BUILD#. Note: You keep using 'localhost'. Why?» #SHORTBUNDLEID# is replaced with “abcsea” (the last component of org.flirble.abcsea) and #BUILD# is replaced by the current build number which is discovered by reading the key CFBundleVersion from the targets Info.plist file.

Not all variables are checked for replaceable values since it is not a trivial process in a shell script. You can check in the script to see which ones are by looking at the contents of variable replacement_options. At the time of writing, this contained:

The replaceable values are:

#PROJECT# Project name (spaces removed)
#APP# or #TARGET# The app/target name (spaces removed)
#CONFIG# The build configuration name (Release, Ad Hoc)
#VERSION# The version number (from CFBundleShortVersionString)
#BUILD# The build number (from CFBundleVersion)
#BUNDLEID# The bundle ID
#SHORTBUNDLEID# The last component of the bundle ID
#PLATFORM# The targetted platform, iphoneos or iphonesimulator

These values can appear anywhere within variables that are inspected, and any number of times.

The result

A picture says it all…

Xcode Build Results

Xcode Build Results with ipa-packager


Note that some files may be downloaded with a .txt file extension to overcome WordPress security checks. Just rename the file if necessary once downloaded.

You don’t need to call it Ad Hoc – the packaging script below contains a configurable value for this name, ADHOC_CONFIG_ADHOC which you are free to change.Powered by Hackadelic Sliding Notes 1.6.5
Powered by Hackadelic Sliding Notes 1.6.5
Powered by Hackadelic Sliding Notes 1.6.5
I’m using localhost just as an example, and to avoid making the URL of my real beta site too public. You should set ADHOC_PUBLISHING_URL to use the hostname of your own website.Powered by Hackadelic Sliding Notes 1.6.5

One thought on “iOS Ad-Hoc Beta publishing directly from Xcode

  1. Pingback: Tweets that mention Chris Luke » Blog Archive » iOS Ad-Hoc Beta publishing directly from Xcode --

Comments are closed.