Skip to content

Instantly share code, notes, and snippets.

@tehnoir
Created April 13, 2016 19:19
Show Gist options
  • Star 15 You must be signed in to star a gist
  • Fork 13 You must be signed in to fork a gist
  • Save tehnoir/4e9efb1f0da45ee54a125d71f4267a68 to your computer and use it in GitHub Desktop.
Save tehnoir/4e9efb1f0da45ee54a125d71f4267a68 to your computer and use it in GitHub Desktop.
Update Xcode project's build settings to point to current provisioning profiles.
#!/bin/bash
##############################################################################################################
### 1. Name your profiles with the convention of ProjectName_TargetName_ConfigurationName.mobileprovision ###
### 2. Create a directory called CodeSign in your project directory ###
### 3. Move all your project's provisioning profiles into the CodeSign directory ###
### ###
### Running this script will update your project file to point to the correct UUIDs of each corresponding ###
### profile in your CodeSign directory. ###
##############################################################################################################
function usage {
echo "Usage: set_project_profiles.sh -m <Profile Map File> -p <Xcode Project File>"
echo "If any arguments are not specified, defaults will be attempted. If defaults don't exist, user will be prompted for value."
echo "OPTIONS:"
echo ' -s: Use when running on Jenkins. Will set the root project directory to ${WORKSPACE}.'
echo " -c <CodeSign Directory>: Relative location of directory containing projects provisioning profiles."
echo " -m <Profile Map File>: Relative location of file which contains target to provisioning profile mappings."
echo " -p <Xcode Project File>: Relative location of Xcode project."
echo " -b: Use PlistBuddy command for UUID replacement instead of sed. (Better handles a couple of edge cases, but makes diffs impossible to read.)"
echo " -x: Show debug logging."
echo " -h: Display usage information."
echo " -v: Verbose logging."
}
plistBuddy="/usr/libexec/PlistBuddy"
profilesDir="${HOME}/Library/MobileDevice/Provisioning Profiles/"
setProfilesWithPlistBuddy=false
verbose=false
useConventionalProfiles=false
while getopts sc:m:p:bxhv option; do
case "${option}" in
s) server=true;;
c) codeSignDirectory=${OPTARG};;
m) profileMapFile=${OPTARG};;
p) xcodeProject=${OPTARG};;
b) setProfilesWithPlistBuddy=true;;
x) set -x;;
v) verbose=true;;
h | help) usage; exit;;
esac
done
function logit() {
if [ $verbose == true ]; then
echo "$@"
fi
}
function checkIfServer {
if [ "$server" == true ]; then
projectRoot="${WORKSPACE}"
else
projectRoot="$PWD"
fi
}
function checkForCodeSignDirectory {
if [ -z "${codeSignDirectory}" ]; then
codeSignDirectory="$projectRoot/CodeSign"
if [ ! -d "${codeSignDirectory}" ]; then
echo "No CodeSign directory found or specified with -c option. Exiting."
exit 1
fi
fi
}
### REMOVE ONCE WE GET RID OF PROFILE MAPS
function checkForProfileMap {
if [ -z "${profileMapFile}" ]; then
if [ -f "$codeSignDirectory/PROFILEMAP" ]; then
profileMapFile=`ls "$codeSignDirectory/PROFILEMAP"`
else
useConventionalProfiles=true
fi
fi
}
function checkForXcodeProject {
if [ -z "${xcodeProject}" ]; then
if [ -f "$codeSignDirectory/XCODEPROJECT" ]; then
xcodeProject=`cat "$codeSignDirectory/XCODEPROJECT"`
else
echo "No XCODEPROJECT file found in CodeSign directory or specified with -p option. Exiting."
exit 1
fi
fi
projectName=`basename "$xcodeProject" | cut -d'.' -f1`
}
function checkForProjectFile {
projectExtension=`basename "$xcodeProject" | cut -d'.' -f2`
if [ "$projectExtension" != "xcodeproj" ]; then
echo "Xcode project should have a .xcodeproj file extension. Instead got a .$projectExtension extension. Exiting."
exit 1
else
projectFile="$xcodeProject/project.pbxproj"
if [ ! -f "$projectFile" ]; then
echo "Project file $projectFile does not exist. Exiting."
exit 1
fi
fi
}
function copyProfiles {
mkdir -p "$profilesDir"
find "$codeSignDirectory" -name *.mobileprovision | egrep '.*' > /dev/null 2>&1
if [ $? -eq 0 ]; then
cp "$codeSignDirectory/"*.mobileprovision "$profilesDir"
if [ $? -ne 0 ]; then
echo "Copying profiles from CodeSign directory failed. Please run script again with -x option for debugging."
exit 1
fi
else
echo "No provisioning profiles found in CodeSign directory: $codeSignDirectory. Will attempt to proceed with profiles already in system profile directory."
fi
}
### REMOVE ONCE WE GET RID OF PROFILE MAPS
function loadProfileMap {
# Dictionary of all targets and corresponding provisioning profiles. Must be defined on a per-project basis.
# Mapping must be must be ordered target:devprofile:adhocprofile:releaseprofile
allProfiles=(`cat "$profileMapFile"`)
}
function getTargets {
rootObject=`$plistBuddy -c "Print :rootObject" $projectFile`
targetList=`$plistBuddy -c "Print :objects:$rootObject:targets" $projectFile | sed -e '/Array {/d' -e '/}/d' -e 's/^[ \t]*//'`
targets=(`echo $targetList`)
}
function setNewProfileUuid {
if [ "$currentProfileUuid" != "$newProfileUuid" ]; then
echo "Changing $configurationName from $currentProfileUuid to $newProfileUuid"
if [ $setProfilesWithPlistBuddy == false ]; then
sed -i '' "s/$currentProfileUuid/$newProfileUuid/g" "$projectFile"
if [ $? -ne 0 ]; then
printf "sed command failed on $cleanTargetName:$configurationName attempting to replace \"$currentProfileUuid\" with \"$newProfileUuid\".\nAborting.\nConsider running script with -b flag to use PlistBuddy instead of sed."
exit 1
fi
elif [ $setProfilesWithPlistBuddy == true ]; then
echo "Detected -b flag, or no profile currently set. Using PlistBuddy instead of sed to set new UUID values..."
if [ $currentProfileUuidIsSet == false ]; then
logit "No PROVISIONING_PROFILE key is defined for $targetName:$configurationName. Adding one..."
$plistBuddy -c "Add :objects:$configurationId:buildSettings:PROVISIONING_PROFILE string $newProfileUuid" "$projectFile"
elif [ $currentProfileUuidIsSet == true ]; then
$plistBuddy -c "Set :objects:$configurationId:buildSettings:PROVISIONING_PROFILE $newProfileUuid" "$projectFile"
fi
fi
else logit "Provisioning Profile UUID is already set to latest. No change made."
fi
}
function getCurrentProfileUuid {
currentProfileUuid=`$plistBuddy -c "Print :objects:$configurationId:buildSettings:PROVISIONING_PROFILE" $projectFile 2> /dev/null`
if [ $? -eq 0 ]; then
currentProfileUuidIsSet=true
if [ $currentProfileUuid == '' ]; then
echo "Current provisioning profile is blank. Unable to replace using sed, proceeding with PlistBuddy instead."
setProfilesWithPlistBuddy=true
fi
else
currentProfileUuidIsSet=false
setProfilesWithPlistBuddy=true
fi
}
function configureProvisioningProfiles {
for targetId in ${targets[@]}; do
targetName=`$plistBuddy -c "Print :objects:$targetId:name" "$projectFile"`
logit "Checking Target: $targetName"
cleanTargetName=${targetName// /_}
buildConfigurationListId=`$plistBuddy -c "Print :objects:$targetId:buildConfigurationList" "$projectFile"`
buildConfigurationList=`$plistBuddy -c "Print :objects:$buildConfigurationListId:buildConfigurations" "$projectFile" | sed -e '/Array {/d' -e '/}/d' -e 's/^[ \t]*//'`
buildConfigurations=(`echo $buildConfigurationList`)
for configurationId in ${buildConfigurations[@]}; do
configurationName=`$plistBuddy -c "Print :objects:$configurationId:name" "$projectFile"`
logit "Checking Configuration: $configurationName"
conventionProfileName=$projectName\_$cleanTargetName\_$configurationName.mobileprovision
logit "Convention Profile Name: $conventionProfileName"
if [ -f "$profilesDir/$conventionProfileName" ]; then
getCurrentProfileUuid
newProfileUuid=`security cms -D -i "$profilesDir/$conventionProfileName" > /tmp/newprofile.plist && /usr/libexec/PlistBuddy -c Print:UUID /tmp/newprofile.plist && rm -f /tmp/newprofile.plist`
setNewProfileUuid
else logit "No provisioning profile set for target $targetName with configuration $configurationName. No change made."
fi
done
done
}
### REMOVE ONCE WE GET RID OF PROFILE MAPS
function setProfilesWithProfileMap {
if [ $setProfilesWithPlistBuddy == true ]; then
echo "Detected -b flag. Using PlistBuddy instead of sed to set new UUID values..."
fi
for targetId in ${targets[@]}; do
targetName=`$plistBuddy -c "Print :objects:$targetId:name" $projectFile`
logit "Checking Target: $targetName"
cleanTargetName=${targetName// /}
for profileList in ${allProfiles[@]}; do
profileTargetName=`awk -F: '{ print $1 }' <<< $profileList`
if [ "$cleanTargetName" == "$profileTargetName" ]; then
developmentProfileName=`awk -F: '{ print $2 }' <<< $profileList`
adHocProfileName=`awk -F: '{ print $3 }' <<< $profileList`
appStoreProfileName=`awk -F: '{ print $4 }' <<< $profileList`
buildConfigurationListId=`$plistBuddy -c "Print :objects:$targetId:buildConfigurationList" $projectFile`
buildConfigurationList=`$plistBuddy -c "Print :objects:$buildConfigurationListId:buildConfigurations" $projectFile | sed -e '/Array {/d' -e '/}/d' -e 's/^[ \t]*//'`
buildConfigurations=(`echo $buildConfigurationList`)
for configurationId in ${buildConfigurations[@]}; do
configurationName=`$plistBuddy -c "Print :objects:$configurationId:name" $projectFile`
logit "Checking Configuration: $configurationName"
if [ "$profileTargetName" == "$cleanTargetName" ]; then
if [ "$configurationName" == "Debug" ]; then
getCurrentProfileUuid
if [ $? -eq 0 ]; then
newProfileUuid=`security cms -D -i $codeSignDirectory/$developmentProfileName > /tmp/newprofile.plist && /usr/libexec/PlistBuddy -c Print:UUID /tmp/newprofile.plist && rm -f /tmp/newprofile.plist`
setNewProfileUuid
else logit "No provisioning profile set for config $configurationName. No change made."
fi
elif [ "$configurationName" == "AdHoc" ]; then
getCurrentProfileUuid
if [ $? -eq 0 ]; then
newProfileUuid=`security cms -D -i $codeSignDirectory/$adHocProfileName > /tmp/newprofile.plist && /usr/libexec/PlistBuddy -c Print:UUID /tmp/newprofile.plist && rm -f /tmp/newprofile.plist`
setNewProfileUuid
else logit "No provisioning profile set for config $configurationName. No change made."
fi
elif [ "$configurationName" == "Release" ]; then
getCurrentProfileUuid
if [ $? -eq 0 ]; then
newProfileUuid=`security cms -D -i $codeSignDirectory/$appStoreProfileName > /tmp/newprofile.plist && /usr/libexec/PlistBuddy -c Print:UUID /tmp/newprofile.plist && rm -f /tmp/newprofile.plist`
setNewProfileUuid
else logit "No provisioning profile set for config $configurationName. No change made."
fi
else logit "Configuration name did not match Debug, AdHoc, or Release. No UUID set."
fi
fi
done
fi
done
done
}
checkIfServer
checkForCodeSignDirectory
checkForProfileMap
checkForXcodeProject
checkForProjectFile
copyProfiles
getTargets
if [ $useConventionalProfiles == true ]; then
configureProvisioningProfiles
else
loadProfileMap
setProfilesWithProfileMap
fi
@fenglh
Copy link

fenglh commented Mar 3, 2017

is there any other way to match the value of CodeSign Identify and the value of Provision Profile ,besides using XCode.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment