Setting a provisioning profile from within xcodebuild when making iPhone apps
Actually, you should be able to just add it to the XCode command line setting.
xcodebuild [whatever other options you have] PROVISIONING_PROFILE="[Your profile Unique ID here]"
Build Settings from the command line are supposed to override everything, so this should win out over anything defined in the project or target.
The provisioning profile has to be provided by UUID, in my case the provisioning profiles are checked in to the source control system, and are therefore checked out with the code by the developer/build server/CI system. In the source tree the profiles have human readable names such as MyApp.mobileprovison and are located in a directory called "ProvisioningProfiles". To create an xcode archive, the profiles have to be renamed and copied to the ~/Library/MobileDevice/Provisioning Profiles directory before xcodebuild will recognize them. This is a code snippet that can be used in a CI build script.
# The keychain needs to be unlocked for signing, which requires the keychain
# password. This is stored in a file in the build account only accessible to
# the build account user
if [ ! -f $HOME/.pass ] ; then
echo "no keychain password file available"
exit 1
fi
case `stat -L -f "%p" $HOME/.pass`
in
*400) ;;
*)
echo "keychain password file permissions are not restrictive enough"
echo "chmod 400 $HOME/.pass"
exit 1
;;
esac
#
# unlock the keychain, automatically lock keychain on script exit
#
security unlock-keychain -p `cat $HOME/.pass` $HOME/Library/Keychains/login.keychain
trap "security lock-keychain $HOME/Library/Keychains/login.keychain" EXIT
#
# Extract the profile UUID from the checked in Provisioning Profile.
#
uuid=`/usr/libexec/plistbuddy -c Print:UUID /dev/stdin <<< \
\`security cms -D -i ProvisioningProfiles/MyApp.mobileprovision\``
#
# Copy the profile to the location XCode expects to find it and start the build,
# specifying which profile and signing identity to use for the archived app
#
cp -f ProvisioningProfiles/MyApp.mobileprovision \
"$HOME/Library/MobileDevice/Provisioning Profiles/$uuid.mobileprovision"
xcodebuild -workspace MyApp.xcworkspace -scheme MyScheme \
-archivePath build/MyApp.xcarchive archive \
PROVISIONING_PROFILE="$uuid" CODE_SIGN_IDENTITY="iOS Distribution"
The keychain must be unlocked and the "/usr/bin/codesign" tool must be allowed access to the private key associated with signing identity for this to work - The following references were used https://stackoverflow.com/a/21327591/2351246 and Add codesign to private key ACL without Keychain for unlocking and adding keychain access for codesign respectively.
If the archive is to be subsequently exported to an IPA using xcodebuild then the following issue must be taken into account (xcodebuild not copying file from .app). The provisioning profile needs to be supplied again. The script snippet to create an IPA is
profileName=`/usr/libexec/plistbuddy -c Print:Name /dev/stdin <<< \
\`security cms -D -i ProvisioningProfiles/MyApp.mobileprovision\``
xcodebuild \
-exportArchive \
-exportFormat IPA \
-archivePath build/MyApp.xcarchive \
-exportPath $IPADIR/MyApp.ipa \
-exportProvisioningProfile "$profileName"
The keychain will have to be unlocked while this command is running.
UPDATE
On OSX Mavericks (v10.9.5) and OSX Yosemite we started seeing code signing errors:
Codesign check fails : ...../MyApp.app: resource envelope is obsolete
Check this posting here for the cause xcodebuild - codesign -vvvv says"resource envelope is obsolete"
To implement the change suggested by Apple Support in the referenced post, run the following command:
sudo perl -pi.bak -e 's/--verify"./--verify", "--no-strict",/ if /codesign.*origApp/;' `xcrun -sdk iphoneos -f PackageApplication`
My solution isn't elegant but it does do the job and let me automate everything on the build server:
#!/bin/bash
TARGET="Your App"
CONFIGURATION="Release"
SDK="iphoneos"
PROFILE_PATH="/Users/jkp/Desktop/foo.mobileprovision"
IDENTITY="iPhone Distribution: Your Company Ltd"
KEYCHAIN="/Users/jkp/Desktop/keychain"
PASSWORD="foobar"
open "${PROFILE_PATH}"
sleep 5
osascript -e "tell application \"Xcode\" to quit"
security unlock-keychain -p ${PASSWORD} ${KEYCHAIN}
xcodebuild \
-target "${TARGET}" \
-configuration ${CONFIGURATION} \
-sdk iphoneos \
CODE_SIGN_IDENTITY="${IDENTITY}" \
OTHER_CODE_SIGN_FLAGS="--keychain ${KEYCHAIN}"
The key thing here is that I didn't need to install the provisioning profile first. I actually have another script that uses mechanize to download the latest copy of the provisioning profile before each build which means we can update the profile (adding new devices for example) remotely and have those changes picked up by our CI server without any extra work.
Note: I've since found a way to install or update a provisioning profile without needing to involve Xcode at all - much cleaner! See here for full details.