Sharing the Code

Programming stuff that might be useful to others

Using Ant to build iOS apps for ad-hoc OTA distribution

I was over in Ireland for Christmas and I needed to do some work on an iPhone app but I don’t have a Mac laptop. I couldn’t get a hackintosh working on my Windows laptop that would run XCode 4. Initially I tried remotely accessing my Mac Mini with a program called iRAPP. It works like Windows Terminal Services so it’s a bit better than the built-in screen sharing (VNC). My broadband connection in Ireland wasn’t brilliant so there was quite a bit of latency but SSH worked fine so I decided to create an Ant script that would upload my source files to the Mac Mini and compile and deploy it to a server so I could install the app on my iPhone using ad-hoc over-the-air distribution.

Below is the bit that builds the app and creates an IPA:

[sourcecode language=”xml”]


user: your username on the mac
keychain.password: your keychain password
projectPath: the path to the project
build: where the IPA file is going to be outputted to
appId: id of the app, it’s the same as your project filename without the xcodeproj extension
appHash: it’s the string after the app name where the app is compiled to e.g: if your app was compiled to:/Users/username/Library/Developer/Xcode/DerivedData/MyApp-bfgcxkrfwxdwfdhdriahyyjvmrnc, the hash would be bfgcxkrfwxdwfdhdriahyyjvmrnc
codeSignIdentity: The code signing identity used in XCode e.g. iPhone Developer: Mark Horgan
${certsPath}/${adHocCert}: path to the provisioning profile (it has a .mobileprovision extension)
xcodeHome: path to XCode e.g. /Applications/

If you are using a workspace it would like this:

[sourcecode language=”xml”]


For the user to be able to install the app on their iPhone you need to create an ad-hoc distribution profile in the iOS Provisioning Portal that includes their device. First you need to add their iPhone under “Devices”. This requires getting their UDID (unique device ID). See here for instructions. And then under “Provisioning” you need to create a distribution ad-hoc provisioning profile. Drag this file onto the XCode icon in the dock.

There are two ways to distribute the IPA:

  1. From your server
  2. Test Flight

Deploy to a server

To serve the IPA from a server you need to generate a plist file. The way to do this is to manually create an ad-hoc build in XCode. Go to Product > Archive in XCode. After creating the archive it should open Archives in the Organizer. If it doesn’t go to Window > Organizer and select the Archives icon. Select the archive you have just made. Then click on the “Share…” button. In the next screen “Contents” should be set to “iOS App Store Package (.ipa)” and “Identity” should be setup ok.

Share options

Click the “Next” button. Set the name and location of the app and check “Save for Enterprise Distribution”. This will show more fields. For the “Application URL” enter the remote URL to the .ipa file.

Generating ipa and plist files

This generates an ipa file (the app file) and a plist file (a kind of manifest file). Lastly you need to create a simple HTML file from where the user can click on a link in Mobile Safari and download and install the app:

[sourcecode language=”html”]

School Zone Safety Install Page

Tap here to install the application


As you can see the page contains a link to the plist file using a special URL format:

Then you just need to upload the ipa, plist and html files to the server.

Below is an example of an Ant script that uploads the IPA to a server:

[sourcecode language=”xml”]


Ant should already be install on your Mac. To run an ant task, open a terminal and goto the directory where your build.xml is located and type:

ant targetName

You can leave out the targetName if you have specified a default target in the project element. To use scp and ssh tasks you will need to download jsch-version.jar (scroll down a bit to Download) and place it in /usr/share/ant/lib.

Deploy to Test Flight

An Ant script to deploy to Test Flight would look something like this:

[sourcecode language=”xml”]



You would need to get the API token and team token from your account in Test Flight.

Comments are closed