Setting a provisioning profile from within xcodebuild when making iPhone apps

77,107

Solution 1

Documentation

It seems from the doc, you can't set the provisioning file BUT you can specify the target:

[-target targetname]

So, if you create a target for each provisioning file, you could select the proper target from the command line.

This would basically accomplish what your asking.

Solution 2

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.

Solution 3

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.

Solution 4

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`

Solution 5

I realize this is probably a little off OP topic, but this question comes up first when searching for how to get Xcode builds working on Jenkins. Posting some additional information here for posterity. And points. If you found this useful, please give points :)

Anyway, went several rounds on this one a couple times lately. Found this:

http://code-dojo.blogspot.co.uk/2012/09/fix-ios-code-signing-issue-when-using.html

Seems to work. Make sure to:

  1. Setup the Xcode build as a regular OSX user first; get it building your distributable from there, fixing any provisioning profile issues through Xcode;

  2. Get the command line build working using xcodebuild, as a regular OSX user;

  3. Then follow the instructions in the post above to the letter, copying all iOS certs from Login Keychain to System and copying ~/Library/MobileDevice/Provisioning Profiles to the Jenkins user's ~jenkins/Library/MobileDevice/Provisioning Profiles folder.

The next Jenkins build, using the commands in step 2 above, should work flawlessly.

Share:
77,107

Related videos on Youtube

gavin
Author by

gavin

Updated on January 05, 2022

Comments

  • gavin
    gavin over 2 years

    I'm using xcodebuild to compile my iPhone app from the command line. Is there a way to pass in some sort of option to set the provisioning profile? There seems to be not very much information about xcodebuild in general.

  • gavin
    gavin almost 15 years
    Thanks. I had seen this, and this isn't as elegant of a solution as I'd like, but I think it'll still work out the way that I want it to.
  • Shade
    Shade about 13 years
    have you had any success in finding a way to add a provisioning profile from the command line in the past few days? It is really frustrating that such a simple thing cannot be done because of the tools' inflexibility...
  • Shade
    Shade about 13 years
    never mind my previous comment. I found the answer in this question: stackoverflow.com/questions/4744959/…
  • Bdebeez
    Bdebeez almost 12 years
    One thing that tripped me up: the setting you see in the XCode interface is actually two settings - PROVISIONING_PROFILE and CODE_SIGN_IDENTITY. If you do client work and have multiple signing identities, be careful to set BOTH of these correctly from the command line.
  • Luke
    Luke over 11 years
    The link in your Note: is dead. Any chance you can post it elsewhere or revive it?
  • Joshua
    Joshua almost 11 years
    Another bump on dead link
  • James Brooks
    James Brooks over 10 years
  • Jonny
    Jonny over 10 years
    You should uncheck this as correct answer. Rob's answer is correct. Just tried it a second ago and I could override the provisioning profile just fine.
  • Zillan
    Zillan over 9 years
    Worked for us! Thanks for the idea!
  • funkybro
    funkybro about 9 years
    One of my favourite SO answers ever, so many fine techniques for iOS build scripts here. Particularly love the method of extracting UUID from *.mobileprovision.
  • Hilen
    Hilen almost 9 years
    How to find the name of PROVISIONING_PROFILE and the name of CODE_SIGN_IDENTITY ?
  • Rob
    Rob almost 9 years
    The UDID of the PROVISIONING_PROFILE comes from the profile itself. The profiles are technically binary files since they contain signature data, but you can still open them in a text editor and look for the UDID: <key>UUID</key> <string>longstring</string>. The CODE_SIGN_IDENTITY is the "common name" field of your certificate which you can see in keychain access.
  • Bob Vork
    Bob Vork over 8 years
    Also, when you have the correct profile selected in xcode, open the profile selection thingy and choose 'Other...' at the bottom. You will get a textfield with the ID of the selected provisioning profile
  • Gorcyn
    Gorcyn about 8 years
    Trying this method gave me an error while generating archive — last command in the first code block. I had to replace PROVISIONING_PROFILE with APP_PROFILE to prevent cocoapods pods to be built with the app provisioning profile. The error I had : The provisioning profile specified in your build settings ("PROVISIONING PROFILE NAME") has an AppID of "APP_ID" which does not match your bundle identifier “org.cocoapods.Alamofire”.
  • dragon788
    dragon788 over 2 years
    It appears his blog might have a copy on Tumblr, vworkdev.tumblr.com/post/160876198/…