51

I'm trying to automate the process of building apps for our clients using bash scripts running on a Mac Mini Server (OSX 10.7).

My script is based on the spectacularly useful script from github originally posted at https://gist.github.com/949831

I'm building the app using xcodebuild, and then signing and embedding the mobileprovision file using xcrun.

When I do all this with a mobileprovision file I manually installed into Xcode using the GUI (e.g. double-clicking) it works fine. If I simply try to use a mobileprovision file copied onto the server with SCP it fails (Code Sign error: Provisioning profile '123abc123' can't be found.)

Presumably this is because the file isn't 'installed'.

Is there any way to install the mobileprovision file from the terminal? I'm using SSH so using things such as the 'open' command won't work.

Thanks!

Ben Clayton
  • 75,781
  • 25
  • 117
  • 124

7 Answers7

83

If you don't want to download external dependencies (like Ben did), the following should work in most cases:

uuid=`grep UUID -A1 -a adhoc.mobileprovision | grep -io "[-A-F0-9]\{36\}"`
cp adhoc.mobileprovision ~/Library/MobileDevice/Provisioning\ Profiles/$uuid.mobileprovision

Note that a UUID is composed of hexadecimal digits so the correct range is [-A-F0-9] and not [-A-Z0-9].

Bonus: Download and install profiles

Using the cupertino tool, the following snippet downloads all your distribution profiles from the Developer Portal and installs them.

ios profiles:download:all --type distribution

for file in *.*provision*; do
    uuid=`grep UUID -A1 -a "$file" | grep -io "[-A-F0-9]\{36\}"`
    extension="${file##*.}"
    echo "$file -> $uuid"
    mv -f "$file" ~/Library/MobileDevice/Provisioning\ Profiles/"$uuid.$extension"
done

cupertino (the ios command) can be installed with sudo gem install cupertino.

Mig82
  • 3,665
  • 1
  • 30
  • 55
nschum
  • 14,984
  • 5
  • 56
  • 56
  • This worked beautifully when I had to install a new provisioning profile in our remote jenkins server hosted in another state. – Matt S. Jul 04 '12 at 02:37
  • Ah.. great! I didn't know you could grep binary file. Nice one. – Ben Clayton Jul 27 '12 at 08:59
  • @BenClayton If you open the file in vim you will see that it is basically a plain text plist with a binary header and footer. Just enough to cause less/more to give you the "view binary file" warning. – Bruno Bronosky Nov 27 '13 at 16:27
  • The binary data is a cryptographic signature. Quoting from [this blog post](http://www.doubleencore.com/2013/04/what-is-a-provisioning-profile-part-1/): "Every Provisioning Profile is really a PKCS#7 signed plist. PKCS stands for Public Key Cryptography Standards. PKCS#7 is the version that supports the Cryptographic Message Syntax. Apple uses these signed plists so the OS can verify that the application being installed is from the right developer and that the content inside the plist has not been modified." – TachyonVortex Jun 20 '14 at 13:59
  • 9
    Instead of using `grep` to extract the UUID, you can use Apple's `security` and `PlistBuddy` tools – see [this answer](http://stackoverflow.com/a/10490095/1851186) – `uuid=$(/usr/libexec/PlistBuddy -c "Print UUID" /dev/stdin <<< $(/usr/bin/security cms -D -i adhoc.mobileprovision))` – TachyonVortex Jun 20 '14 at 14:10
  • Actually, since the UUID is composed of hexadecimal digits, the range of alphabetical characters goes from A to F, not from A to Z. So the proper `grep` pattern is `[-A-F0-9]\{36\}`. Also, the Cupertino tool has announced in their `README.md` file that it doesn't currently work. – Mig82 Oct 11 '17 at 09:50
  • I've noticed in MacOS Sierra you need to use extended regexes in grep, with the `-E` switch for this to work. – nik Jan 24 '18 at 03:13
  • Note that the above fails if you have never installed a provisioning profile manually, as Xcode does not create the destination path until it needs it. – NateEag Oct 08 '18 at 15:32
28

Since asking this question, I've built a solution myself. The secret is to simply copy the file to the ~/Library/MobileDevice/Provisioning Profiles/ folder, but (here's the tricky bit) renamed to [The UUID].mobileprovision.

The UUID is held inside a text part of the file itself (in a plist). Unfortunately, the file also includes binary so 'defaults read' cannot read it. Luckily this guy has built a small command line utility to get the UUID (and some other things out again).

Here's my full working script:

https://gist.github.com/2568707

Ben Clayton
  • 75,781
  • 25
  • 117
  • 124
7

A compendium of all other answers update_provisioning_profile.sh:

#!/bin/sh
#
# Download and install a single iOS provisioning profile
# Requires https://github.com/nomad/cupertino
#
# Usage
# - Login to your account once:
# ios login
# - Configure TEAM and PROFILE (instructions below)
# - Run update_provisioning_profile.sh at anytime, usually after adding/removing devices to the profile

# Configure the team identifier
# Copy it from developer portal or just use cupertino to get it:
# ios devices
# Copy the string in parens and set it as TEAM
TEAM="team id"

# Configure the profile name you want to manage
# Copy it from developer portal or use cupertino to get a list (ignoring Xcode managed profiles):
# ios profiles --team ${TEAM} | grep -v 'iOS Team Provisioning Profile'
# Copy the name as-is and set as PROFILE
PROFILE="profile name"

# Fetch the profile using `cupertino` tool
# you need to run `ios login` once to setup the account
ios profiles:download "${PROFILE}" --team ${TEAM}
PROFILE_FILE=`echo $PROFILE | tr ' ' '_'` # `cupertino` tool will replace spaces with _
UUID=`/usr/libexec/PlistBuddy -c 'Print :UUID' /dev/stdin <<< $(security cms -D -i ${PROFILE_FILE}.mobileprovision)`

# copy where Xcode can find it
cp ${PROFILE_FILE}.mobileprovision "$HOME/Library/MobileDevice/Provisioning Profiles/${UUID}.mobileprovision"

# clean
rm ${PROFILE_FILE}.mobileprovision

Easy to adapt to your provisioning needs.

djromero
  • 19,281
  • 4
  • 67
  • 67
  • 1
    Cupertino stopped working due to a recent change on the Apple Developer Portal. A maintained alternative is to use spaceship to communicate with Apple's Developer back-end, or use any of the fastlane tools, like match or sigh. https://github.com/nomad/cupertino – AnneTheAgile Feb 14 '17 at 23:17
3

We run our builds in Jenkins and had a similar problem. Our Ad Hoc provisioning profile changes quite often and we don't want to run around to each of our build slaves installing them in xcode every time they change, so here's what I got to work:

/usr/bin/xcrun -sdk iphoneos PackageApplication -v <path to yourapp.app> -o <path to your .ipa file> --sign "<Name of signing identity>" --embed <path to .mobileprovision file>

The "" is what you see under "Code Signing" section in the Build Settings of your target.

jpancoast
  • 451
  • 2
  • 6
  • That's interesting, thanks! Unfortunately, that approach didn't work for me as I was trying to automatically build for a new client each time (e.g. the 'Name of signing identity' would change for each build, unlike your case) and xcodebuild wouldn't find their provisioning profile unless I performed the 'install' step using the script in my answer. – Ben Clayton May 03 '12 at 09:19
3

Looks like Apple added empty line in the .mobileprovision provisioning profile file below each key-value pair and the grep option doesn't not work anymore.

Here's how to retrieve it with PlistBuddy and security using a python script

command = "/usr/libexec/PlistBuddy -c 'Print :UUID' /dev/stdin <<< $(security cms -D -i abc.mobileprovision)"
uuid = os.popen(command).readline().rstrip('\n')
indiantroy
  • 1,473
  • 1
  • 14
  • 25
  • I can confirm that Apple added an empty line below each key-value pair. But since it's not between key and value, grepping still works for every file I've tested. – nschum Aug 20 '14 at 07:56
  • @nschum, I might have an issue with grep then. But anyways I think the approach I am using now is better than the text search in case if Apple makes further changes to the provisioning profile format. – indiantroy Aug 20 '14 at 19:54
  • @nschum, I just checked the grep I was using and it exactly looks like how you had it in your original answer. It was broken for me and the provisioning profile got an empty name after renaming. – indiantroy Aug 20 '14 at 19:59
  • I just noticed some provisioning profiles now have lower case UUIDs. That might have been the cause in that case. – nschum Aug 25 '14 at 20:11
2

Use fastlane sigh to install a particular provisional file or you can create a new one.

fastlane sigh renew --adhoc -n "provisional-profile-name" --app_identifier "app-identifier" -u "user-name" --ignore_profiles_with_different_name

provisional-profile-name is just name of the profile, doesn't contain the .mobileprovision extension.

To create a new adhoc profile with all the device UUIDs added,

fastlane sigh --adhoc --app_identifier "app-identifier" -u "username"

Fastfile,

lane :build do

sigh(
adhoc: true,
app_identifier: "***APP_ID**",
provisioning_name: "**Profile_name**",
username: "Apple_ID",
force: true,
skip_certificate_verification: true,
)


gym(
#export_options: "exportPlist.plist",
scheme: "**scheme-name**",
export_method: "ad-hoc",
xcargs: "PROVISIONING_PROFILE=$SIGH_UUID",
)
end
Vineeth
  • 555
  • 1
  • 7
  • 16
1

It looks like there hasn't been any recent development on cupertino. Fastlane has a tool called sigh to manage provisioning profiles (create, download, renew, repair): https://github.com/fastlane/fastlane/tree/master/sigh#readme

Toland Hon
  • 4,179
  • 2
  • 28
  • 34