package_adhoc.sh is a packaging script for iPhone Ad Hoc distribution builds.
Download: package_adhoc.sh
Before submitting an iPhone app to the store, I had to send out Ad Hoc builds to beta testers. There are very complicated, manual ways to create Ad Hoc builds (using the Finder and Xcode and a mouse), but I made an Ad Hoc packaging script which I will share with you.
How does it work? First let’s look at the ship/install process.
How I Ship a Provisioned Ad Hoc Build
- Increment App Bundle Version number in Xcode
Resources -> Info.plist -> Bundle Version
Update to latest version number eg 1.154
- Copy asset files from app directory to package dist directory (only have to do this once)
$ cd ~/work/HelloWorld
$ cp *.mobileprovision iTunesArtwork README.txt HISTORY.txt _distfiles/
package_adhoc will include all of the files in this directory in my distribution build’s .zipfile
- Run packaging script to create provisioned AdHoc distribution build package (optionally specify build configuration)
$ ./package_adhoc.sh HelloWorld_v154 Debug
- Distribute the distribution build .zipfile to your beta testers
$ scp _release/HelloWorld_v154.zip webadmin@website.com:public_html/
As you can see, it’s a quick process that allows me to ship builds fast and frequently. Beta testers can download my distribution package and installation is as quick-and-painless as Apple allows it to be.
How My Beta Testers Install a Provisioned Ad Hoc Build
- Download and open Ad Hoc distribution package
$ wget http://website.com/HelloWorld_v154.zip
- Drag .mobileprovision cert into iTunes
Tester only has to do this once, unless cert is updated.
- Double click HelloWorld.ipa
iTunes will install the Ad Hoc app to Applications
- Sync your mobile device
iTunes will install the Ad Hoc provisioned release
What a fast, automated deployment process!
Certificate Updating for New Device IDs
When I get a new beta tester's Device ID, shipping a new build for them is as "simple" as adding their Device ID to my app's iphone dev portal, generating a new .mobileprovision cert, downloading and installing it in xcode, and running the package_adhoc.sh script. It really pays to have some sort of Ad Hoc build packaging script- why not use the general-purpose one I wrote?
Get Started using package_adhoc.sh
To get started using package_adhoc.sh to automate the Ad Hoc build packaging process, there are three pre-requisites:
- A. Create an Ad Hoc Distribution Provisioning Profile via Apple's website
- B. Create an Ad Hoc build configuration in Xcode.
- C. Download and configure package_adhoc.sh
You are probably familiar with the first two if you are already making Ad Hoc builds.
A. Create Ad Hoc Distribution Provisioning Profile
To run your app on another mobile device, you must first set up a development certificate on Apple's iphone portal Website, as well as an Ad Hoc Distribution Provisioning Profile. You then need to register the mobile device's Device ID with the same website, adding the new Device ID(s) to this Ad-Hoc distribution certificate. You subsequently download the .mobileprovision certificate and install in Xcode, which uses it to codesign the app to run on those Device IDs. The app is built with an Ad Hoc-specific configuration which references this distribution certificate. You will also be distributing the signed certificate with your Ad Hoc installer.
To create an Ad Hoc .mobileprovision distribution certificate:
- Set up your Development Certificate through iPhone Dev Program Portal
Publishing Applications for Testing
- Get Beta Tester's Device ID
Instructions for Application Testing - Sending Your Device ID to a Developer
- Add Device ID to your App on Apple's website
iPhone Developer Program Portal
Devices -> Add Devices
- Create Ad Hoc Distribution Provisioning Profile on Apple's WebsiteDistribution Provisioning Profiles
Provisioning > Distribution > New Profile
Select App ID, Device IDs of your testers, and Submit.
- Download and Install Ad Hoc Distribution Provisioning Profile
Wait for cert (.mobileprovision) to generate, then download to your desktop. Drag into Xcode.
B. Create Ad Hoc Build Configuration in Xcode
Creating a custom Ad Hoc build configuration in Xcode is the easiest way to associate your new Ad Hoc distribution provision profile (cert) with the build packaging process.
To create an "Ad Hoc" build configuration in xcode:
- Create a new Build Configuration for Ad Hoc
Project > Edit Project Settings > Configurations
Highlight Release configuration, you will copy this and use it for the Ad Hoc configuration.
Duplicate > Rename
Rename configuration from Release copy to Ad Hoc.
- Create a new Entitlements.plist - required for Ad Hoc builds (skip if done already)
File > New File > iPhone OS : Code Signing > Entitlements
Name file Entitlements.plist
- Set Entitlements.plist property for Ad Hoc build
Resources > Entitlements.plist
make sure get-task-allow is unchecked (disallow gdb attach)
- Set Ad Hoc Build Configuration Build Settings
Project > Edit Project Settings > Build > Configuration : Ad Hoc
Set the following build settings for this Configuration:
Code Signing Entitlements
Set this property to Entitlements.plist, including this file in the Ad Hoc build configuration.
Code Signing Identity > Any iPhone OS Device
Click and select the Ad Hoc provisioning profile you installed
eg "iPhone Distribution : Your App Name"
- Save new Ad Hoc build configuration
File > Save
C. Download and configure package_adhoc.sh
- Copy package_adhoc.sh to your project directory
Download package_adhoc.sh.txt and rename to .sh
- Copy asset files from app directory to package dist directory (only have to do this once)
$ cd ~/work/HelloWorld
$ cp *.mobileprovision iTunesArtwork README.txt HISTORY.txt _distfiles/
- Run package_adhoc.sh
$ ./package_adhoc.sh HelloWorld_v154 "Ad Hoc"
Ad Hoc Package Contents
Let's examine the contents of the distribution build that package_adhoc.sh made.
HelloWorld_v154.zip contents:
- README.txt - notes to your testers
- HISTORY.txt - changelog, revision timeline
- HelloWorld.mobileprovision - Ad Hoc build certificate
- HelloWorld.ipa - zipfile loaded into iTunes
HelloWorld.ipa contents:
- HelloWorld.app/ - iPhone app bundle directory
- iTunesArtwork - 512x512 png used by iTunes
How package_adhoc.sh works
I will now walk through the code of the packaging script and describe how it works in three parts:
- Determine release name + build configuration from commandline
- Locate or build iPhone app bundle dir for given build configuration
- Create release package (distrubution build) from app bundle dir + supporting files
1. Determine Release name + Build Configuration
Here is the first third of the package_adhoc.sh script:
#!/bin/sh
# package_adhoc.sh - create provisioned ad-hoc release for iPhone app
# (K) 2009 - mr_marc@makerlab.org - http://iphonedevblog.makerlab.org
#
# default configuration, overwritten from commandline
CONFIGURATION="Ad Hoc" # or Release or Debug
# location of files included in dist (.mobileprovision, iTunesArtwork, README)
DISTDIR="_distfiles"
usage ()
{
echo "usage: $0 release_name [build_configuration]"
echo "ex: $0 HelloWorld_v153"
echo "ex: $0 HelloWorld_v154 Debug"
exit;
}
build_xcode ()
{
xcodebuild -configuration "$CONFIGURATION"
}
# MUST SET directory for release to be packaged
RELEASE="$1"
if test "$RELEASE"x = x; then
usage
fi
# OVERWRITE don't allow removing of previous packaged releases
RELEASEBASE="_release"
RELEASEDIR="$RELEASEBASE/$RELEASE"
if test -d "$RELEASEDIR"; then
echo "ERROR: $RELEASEDIR already exists, erase it"
usage
fi
# CONFIGURATION for xcode build can be overridden from commandline
NEWCONFIG="$2"
if ! test "$NEWCONFIG"x = x; then
CONFIGURATION="$NEWCONFIG"
fi
# XCODE check build available for specified configuration
CHECKCONFIGURATION=`xcodebuild -list | egrep "$CONFIGURATION($|\ )"`
if test "$CHECKCONFIGURATION"x = x; then
echo "ERROR: xcodebuild could not find configuration $CONFIGURATION"vim pack
echo
xcodebuild -list
echo
usage
fi
This first part of the script mostly does arg checking and function definition
- Name for this distribution build MUST be specified on the commandline eg HelloWorld_v154
- Alternate build configuration (default: Ad Hoc) can be specified on commandline
- Cannot create a build of the same name (if HelloWorld_v154 exists, you must change to HelloWorld_v154a)
- Check for a valid build configuration by looking at output from xcodebuild -list, and bail if configuration not found
- xcodebuild function definition: reads valid build configuration, used in 2nd part of script only if application cannot be found and must be built
2. Locate or build iPhone app for given build configuration
Here is the second third of the package_adhoc.sh script:
#######
echo "=== Building distribution package for $RELEASE"
# XCODE make sure buildpath exists for configuration, build if missing
BUILDPATH="build/$CONFIGURATION-iphoneos/"
if test ! -d "$BUILDPATH"; then
echo "missing $CONFIGURATION build dir in $BUILDPATH, trying to build"
build_xcode
if test ! -d "$BUILDPATH"; then
echo "ERROR: xcodebuild could not build configuration $CONGIRUATION ($BUILDPATH)"
usage
fi
echo "=== Successfully built configuration $CONFIGURATION ($BUILDPATH)"
fi
# HACK : accomodate configurations with spaces, chdir to determine app name
cd "$BUILDPATH"
# derive name of .app dir (application)
APPDIR=`ls -d *.app`
cd ../..
APPPATH="$BUILDPATH/$APPDIR"
if test "$APPDIR"x = x; then
APPPATH="$BUILDPATH/.app"
fi
# XCODE make sure app dir exists in buildpath, build if missing
if test ! -d "$APPPATH"; then
echo "missing $APPPATH build in $BUILDPATH, trying to build"
build_xcode
# HACK : accomodate configurations with spaces, chdir to determine app name
cd "$BUILDPATH"
# derive name of .app dir (application)
APPDIR=`ls -d *.app`
cd ../..
# check again for APPDIR/APPPATH
APPPATH="$BUILDPATH/$APPDIR"
if test "$APPDIR"x = x; then
APPPATH="$BUILDPATH/.app"
fi
if test ! -d "$APPPATH"; then
echo "ERROR: xcodebuild could not build $APPPATH configuration $CONGIRUATION ($BUILDPATH)"
usage
fi
echo "=== Successfully built $APPDIR configuration $CONFIGURATION ($BUILDPATH)"
fi
This part of the script determines the app bundle path and builds the app if necessary.
- xcodebuild is triggered by either the build path or the app bundle not existing
- First, look for build configuration path under build- if not found, fire off build
- Next, try and determine App bundle name within build path- if not found, fire off build
- If the build fails, the whole package_adhoc.sh script fails
- Since my Build Path has a space in it (Ad Hoc), I have to do some chdir to determine if an app name exists
- The App bundle should now be built and we should have a path to it, used in 3rd+final part of script to build distribution package.
3. Create release package (distrubution build zipfile) from compiled app
Here is the last third of the package_adhoc.sh script:
# Create directory for release package
echo " - Creating release dir"
mkdir -p "$RELEASEDIR"
# Copy other files
cp $DISTDIR/* "$RELEASEDIR"
# .IPA file: iphone app archive file, installable by itunes
IPA=`echo $APPDIR | sed "s/\.app/\.ipa/"`
echo " - Creating $IPA payload"
mkdir -p "$RELEASEDIR/Payload/"
# Copy built .app to payload/ itunes-specific install dir
cp -rp "$APPPATH" "$RELEASEDIR/Payload/"
# Build .IPA file
# this is just a zipfile with a payload/ dir with the .app, and artwork
cd "$RELEASEDIR"
# include 512x512 png of artwork, if foudn
if test -f "iTunesArtwork"; then
zip -r $IPA iTunesArtwork Payload/
rm -rf Payload iTunesArtwork
else
zip -r $IPA Payload/
rm -rf Payload
fi
cd ..
# Create .zip packaged Distribution
echo " - Compressing release"
zip -r "$RELEASE.zip" "$RELEASE"
echo "=== Build complete for $RELEASEBASE/$RELEASE.zip"
This final part of the script creates the .zipfile for the distribution build package:
- Create new directory in _release folder for this new distribution build
- Copy non-app bundle files from DISTDIR to new distribution build directory (iTunesArtwork, README, and .mobileprovision files)
- Copy compiled application to a Payload/ subfolder- iTunes knows to look for this dir in the .ipa file
- Create IPA archive - iTunesArtwork at top level if available, subfolder of Payload/ with Application bundle dir
- Once IPA archive is created, remove iTunesArtwork and Payload/ from distribution build directory (won't get included in zipfile)
- Create distribution build zipfile- Just compresses the distribution build directory
Your new distribution build is created in the _release folder, eg:
~/work/HelloWorld/_release/HelloWorld_v154.zip
Conclusion + Next Steps
This process works pretty well for me- but I like assigning version numbers to distribution builds manually. What else could this packaging script do to make your life easy?
- Automatically generate release version numbers for the build
eg HelloWorld_20091215, HelloWorld_20091215a
- Automatically update Version Number in Info.plist
I like having manual control of this through Xcode
- Integrate subversion checkout of latest code, use a fresh build tree everytime
- What Else?
Troubleshooting Ad Hoc Builds : Helpful Bookmarks
Some great links that helped me understand the Ad Hoc build process:
Support Free Scripts
If you find this script useful, please post a comment and/or buy my iPhone app: Deadpool from which I extracted this code. (pending App Store approval)
Packaging script for iPhone Ad Hoc distribution builds
package_adhoc.sh is a packaging script for iPhone Ad Hoc distribution builds.
Download: package_adhoc.sh
Before submitting an iPhone app to the store, I had to send out Ad Hoc builds to beta testers. There are very complicated, manual ways to create Ad Hoc builds (using the Finder and Xcode and a mouse), but I made an Ad Hoc packaging script which I will share with you.
How does it work? First let’s look at the ship/install process.
How I Ship a Provisioned Ad Hoc Build
Resources -> Info.plist -> Bundle VersionUpdate to latest version number eg 1.154
$ cd ~/work/HelloWorld$ cp *.mobileprovision iTunesArtwork README.txt HISTORY.txt _distfiles/package_adhoc will include all of the files in this directory in my distribution build’s .zipfile
$ ./package_adhoc.sh HelloWorld_v154 Debug$ scp _release/HelloWorld_v154.zip webadmin@website.com:public_html/As you can see, it’s a quick process that allows me to ship builds fast and frequently. Beta testers can download my distribution package and installation is as quick-and-painless as Apple allows it to be.
How My Beta Testers Install a Provisioned Ad Hoc Build
$ wget http://website.com/HelloWorld_v154.zipTester only has to do this once, unless cert is updated.
iTunes will install the Ad Hoc app to Applications
iTunes will install the Ad Hoc provisioned release
What a fast, automated deployment process!
Certificate Updating for New Device IDs
When I get a new beta tester's Device ID, shipping a new build for them is as "simple" as adding their Device ID to my app's iphone dev portal, generating a new .mobileprovision cert, downloading and installing it in xcode, and running the package_adhoc.sh script. It really pays to have some sort of Ad Hoc build packaging script- why not use the general-purpose one I wrote?
Get Started using package_adhoc.sh
To get started using package_adhoc.sh to automate the Ad Hoc build packaging process, there are three pre-requisites:
You are probably familiar with the first two if you are already making Ad Hoc builds.
A. Create Ad Hoc Distribution Provisioning Profile
To run your app on another mobile device, you must first set up a development certificate on Apple's iphone portal Website, as well as an Ad Hoc Distribution Provisioning Profile. You then need to register the mobile device's Device ID with the same website, adding the new Device ID(s) to this Ad-Hoc distribution certificate. You subsequently download the .mobileprovision certificate and install in Xcode, which uses it to codesign the app to run on those Device IDs. The app is built with an Ad Hoc-specific configuration which references this distribution certificate. You will also be distributing the signed certificate with your Ad Hoc installer.
To create an Ad Hoc .mobileprovision distribution certificate:
Publishing Applications for Testing
Instructions for Application Testing - Sending Your Device ID to a Developer
iPhone Developer Program Portal
Devices -> Add DevicesProvisioning > Distribution > New ProfileSelect App ID, Device IDs of your testers, and Submit.
Wait for cert (.mobileprovision) to generate, then download to your desktop. Drag into Xcode.
B. Create Ad Hoc Build Configuration in Xcode
Creating a custom Ad Hoc build configuration in Xcode is the easiest way to associate your new Ad Hoc distribution provision profile (cert) with the build packaging process.
To create an "Ad Hoc" build configuration in xcode:
Project > Edit Project Settings > ConfigurationsHighlight Release configuration, you will copy this and use it for the Ad Hoc configuration.
Duplicate > RenameRename configuration from Release copy to Ad Hoc.
File > New File > iPhone OS : Code Signing > EntitlementsName file Entitlements.plist
Resources > Entitlements.plistmake sure get-task-allow is unchecked (disallow gdb attach)
Project > Edit Project Settings > Build > Configuration : Ad HocSet the following build settings for this Configuration:
Code Signing EntitlementsSet this property to Entitlements.plist, including this file in the Ad Hoc build configuration.
Code Signing Identity > Any iPhone OS DeviceClick and select the Ad Hoc provisioning profile you installed
eg "iPhone Distribution : Your App Name"
File > SaveC. Download and configure package_adhoc.sh
Download package_adhoc.sh.txt and rename to .sh
$ cd ~/work/HelloWorld$ cp *.mobileprovision iTunesArtwork README.txt HISTORY.txt _distfiles/$ ./package_adhoc.sh HelloWorld_v154 "Ad Hoc"Ad Hoc Package Contents
Let's examine the contents of the distribution build that package_adhoc.sh made.
HelloWorld_v154.zip contents: - README.txt - notes to your testers - HISTORY.txt - changelog, revision timeline - HelloWorld.mobileprovision - Ad Hoc build certificate - HelloWorld.ipa - zipfile loaded into iTunes HelloWorld.ipa contents: - HelloWorld.app/ - iPhone app bundle directory - iTunesArtwork - 512x512 png used by iTunesHow package_adhoc.sh works
I will now walk through the code of the packaging script and describe how it works in three parts:
1. Determine Release name + Build Configuration
Here is the first third of the package_adhoc.sh script:
#!/bin/sh # package_adhoc.sh - create provisioned ad-hoc release for iPhone app # (K) 2009 - mr_marc@makerlab.org - http://iphonedevblog.makerlab.org # # default configuration, overwritten from commandline CONFIGURATION="Ad Hoc" # or Release or Debug # location of files included in dist (.mobileprovision, iTunesArtwork, README) DISTDIR="_distfiles" usage () { echo "usage: $0 release_name [build_configuration]" echo "ex: $0 HelloWorld_v153" echo "ex: $0 HelloWorld_v154 Debug" exit; } build_xcode () { xcodebuild -configuration "$CONFIGURATION" } # MUST SET directory for release to be packaged RELEASE="$1" if test "$RELEASE"x = x; then usage fi # OVERWRITE don't allow removing of previous packaged releases RELEASEBASE="_release" RELEASEDIR="$RELEASEBASE/$RELEASE" if test -d "$RELEASEDIR"; then echo "ERROR: $RELEASEDIR already exists, erase it" usage fi # CONFIGURATION for xcode build can be overridden from commandline NEWCONFIG="$2" if ! test "$NEWCONFIG"x = x; then CONFIGURATION="$NEWCONFIG" fi # XCODE check build available for specified configuration CHECKCONFIGURATION=`xcodebuild -list | egrep "$CONFIGURATION($|\ )"` if test "$CHECKCONFIGURATION"x = x; then echo "ERROR: xcodebuild could not find configuration $CONFIGURATION"vim pack echo xcodebuild -list echo usage fiThis first part of the script mostly does arg checking and function definition
2. Locate or build iPhone app for given build configuration
Here is the second third of the package_adhoc.sh script:
####### echo "=== Building distribution package for $RELEASE" # XCODE make sure buildpath exists for configuration, build if missing BUILDPATH="build/$CONFIGURATION-iphoneos/" if test ! -d "$BUILDPATH"; then echo "missing $CONFIGURATION build dir in $BUILDPATH, trying to build" build_xcode if test ! -d "$BUILDPATH"; then echo "ERROR: xcodebuild could not build configuration $CONGIRUATION ($BUILDPATH)" usage fi echo "=== Successfully built configuration $CONFIGURATION ($BUILDPATH)" fi # HACK : accomodate configurations with spaces, chdir to determine app name cd "$BUILDPATH" # derive name of .app dir (application) APPDIR=`ls -d *.app` cd ../.. APPPATH="$BUILDPATH/$APPDIR" if test "$APPDIR"x = x; then APPPATH="$BUILDPATH/.app" fi # XCODE make sure app dir exists in buildpath, build if missing if test ! -d "$APPPATH"; then echo "missing $APPPATH build in $BUILDPATH, trying to build" build_xcode # HACK : accomodate configurations with spaces, chdir to determine app name cd "$BUILDPATH" # derive name of .app dir (application) APPDIR=`ls -d *.app` cd ../.. # check again for APPDIR/APPPATH APPPATH="$BUILDPATH/$APPDIR" if test "$APPDIR"x = x; then APPPATH="$BUILDPATH/.app" fi if test ! -d "$APPPATH"; then echo "ERROR: xcodebuild could not build $APPPATH configuration $CONGIRUATION ($BUILDPATH)" usage fi echo "=== Successfully built $APPDIR configuration $CONFIGURATION ($BUILDPATH)" fiThis part of the script determines the app bundle path and builds the app if necessary.
3. Create release package (distrubution build zipfile) from compiled app
Here is the last third of the package_adhoc.sh script:
# Create directory for release package echo " - Creating release dir" mkdir -p "$RELEASEDIR" # Copy other files cp $DISTDIR/* "$RELEASEDIR" # .IPA file: iphone app archive file, installable by itunes IPA=`echo $APPDIR | sed "s/\.app/\.ipa/"` echo " - Creating $IPA payload" mkdir -p "$RELEASEDIR/Payload/" # Copy built .app to payload/ itunes-specific install dir cp -rp "$APPPATH" "$RELEASEDIR/Payload/" # Build .IPA file # this is just a zipfile with a payload/ dir with the .app, and artwork cd "$RELEASEDIR" # include 512x512 png of artwork, if foudn if test -f "iTunesArtwork"; then zip -r $IPA iTunesArtwork Payload/ rm -rf Payload iTunesArtwork else zip -r $IPA Payload/ rm -rf Payload fi cd .. # Create .zip packaged Distribution echo " - Compressing release" zip -r "$RELEASE.zip" "$RELEASE" echo "=== Build complete for $RELEASEBASE/$RELEASE.zip"This final part of the script creates the .zipfile for the distribution build package:
Your new distribution build is created in the _release folder, eg:
~/work/HelloWorld/_release/HelloWorld_v154.zipConclusion + Next Steps
This process works pretty well for me- but I like assigning version numbers to distribution builds manually. What else could this packaging script do to make your life easy?
eg HelloWorld_20091215, HelloWorld_20091215a
I like having manual control of this through Xcode
Troubleshooting Ad Hoc Builds : Helpful Bookmarks
Some great links that helped me understand the Ad Hoc build process:
Support Free Scripts
If you find this script useful, please post a comment and/or buy my iPhone app: Deadpool from which I extracted this code. (pending App Store approval)