Command line Update of Provisioning Profiles

I couldn't find anything on this (maybe I'm just using the wrong search terms..):
We're trying to build a sensible continuous integration setting for our apps. To have a REALLY sensible implementation, the build server should be able to automatically refresh the used provisioning profiles from apple. Similar to what the X-Code organizer does, but automagically via command line.
Any clue if that's possible at all?


Solution 1:

Here's my bash script for it, where the first argument to the script ($1) is the location of the new profiles.

rm -Rf ~/Library/MobileDevice/Provisioning\ Profiles/*
cp "$1"/*.* ~/Library/MobileDevice/Provisioning\ Profiles/

Basically, anything in that ~/Library/MobileDevice/Provisioning Profiles/ folder can be used to build with (and will show up in Xcode).

If you're looking to stand up a CI system, I recently gave a talk on using Hudson for it, and put up some slides and notes over here. My email is on my site if you have any questions about it.

Solution 2:

Update: Cupertino will no longer work on latest iTunes. Look into using sigh instead


Sounds like this command line interface will help out big time:

https://github.com/nomad/cupertino

which allows you to download all distribution profiles like so (thanks @tdubik):

ios profiles:download:all --type distribution

Another approach would be to use an Enterprise development license ($300/year) that lets you build for devices without provisioning! So you can build your app, and send it to a device without ever needing to go to the Apple Dev center or register any new devices.

Note that this wouldn't allow you to distribute your app to the appstore, but if you're a development house that builds tons of apps for clients, it may ease your "build and send to clients" process quite a piece! I'm not sure if this would be in Apple's legitimate use policies or not, so please check that out before considering that option. But it might be something to consider for prototypes, etc, and when they actually want to ship it, you get them to get their own developer program license.

Solution 3:

Try using apple_dev_center.rb from https://github.com/lacostej/apple-dev

It parses the info from the apple developer web site and download the profiles for you to copy them to the proper location automatically.

Solution 4:

I have been trying to make this work for sometime. Finally made it!!

Can use fastlane sigh to download and install only the provisional profile you need.

fastlane sigh renew --adhoc -n "provisional_profile_name"
--app_identifier "your_app_identifier" -u "apple_login _username" --ignore_profiles_with_different_name

Note : This command needed any provisional profile of the app already installed in the system. It thrown error for me otherwise.

provisional_profile_name = Just the name of the profile name, doesn't need extension.

Solution 5:

Sigh can manage provisioning profiles for you. However, it doesn't support installing profiles that you've fetched yourself already. However, I still found it valuable to look at their source for how they actually install a profile once they've downloaded it.

Thankfully, it's very similar to James J's answer:

def self.install_profile(profile)
  UI.message "Installing provisioning profile..."
  profile_path = File.expand_path("~") + "/Library/MobileDevice/Provisioning Profiles/"
  uuid = ENV["SIGH_UUID"] || ENV["SIGH_UDID"]
  profile_filename = uuid + ".mobileprovision"
  destination = profile_path + profile_filename

  # If the directory doesn't exist, make it first
  unless File.directory?(profile_path)
    FileUtils.mkdir_p(profile_path)
  end

  # copy to Xcode provisioning profile directory
  FileUtils.copy profile, destination

  if File.exist? destination
    UI.success "Profile installed at \"#{destination}\""
  else
    UI.user_error!("Failed installation of provisioning profile at location: #{destination}")
  end
end

I have a script to perform this local installation for me:

#!/bin/bash -euo pipefail

BASH_SOURCE_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"

cd "$BASH_SOURCE_DIR"

# by default bash passes the glob characters if nothing matched the glob
# disable that
# http://stackoverflow.com/a/18887210/9636
shopt -s nullglob
# this creates a proper bash array, which we need since our profiles
# have funny characters in them
MOBILE_PROVISIONS=(*.mobileprovision)
# re-enable default nullglob behavior
shopt -u nullglob

# On a brand new machine that has never run any app on a development device
# the ~/Library/MobileDevice/"Provisioning Profiles" directory doesn't exist
mkdir -p ~/Library/MobileDevice/"Provisioning Profiles"

for mobileprovision in "${MOBILE_PROVISIONS[@]}"
do
  uuid=$( ./uuid-from-mobileprovision.bash "${mobileprovision}" )
  cp "${mobileprovision}" ~/Library/MobileDevice/"Provisioning Profiles"/"${uuid}".mobileprovision
done

which depends on another uuid-from-mobileprovision.bash script:

#!/bin/bash -euo pipefail

if [ ! -f "${1}" ]
then
  echo "Usage: $0 <path/to/mobileprovision/file>" 1>&2
  exit 1
fi

UUID=$( grep --text --after-context=1 UUID "${1}" | grep --ignore-case --only-matching "[-A-Z0-9]\{36\}" )
if [ -z "${UUID}" ]
then
  echo "Invalid mobileprovision file: ${1}" 1>&2
  exit 2
else
  echo "${UUID}"
fi