I have an Xcode config file, Config.xcconfig that contains this row only:
BUILD_DATE=`date "+%B %Y"`
I added this configuration to project in correct way, i hope.
I want to use the content of BUILD_DATE variable in the Application-info.plist file. How?
I tried get value using ${BUILD_DATE} but result is the string ``date "+%B %Y"` not the value!
From terminal, result is correct:
alp$ BUILD_DATE=`date "+%B %Y"`
alp$ echo $BUILD_DATE
March 2013
alp$
but in Xcode no!
How can i fix this?
You cannot get the build date using the backtick command as the .xcconfig file is not interpreted as a shell script.
Your best bet is to use a similar approach the Bump Build Number script in this SO question (that I asked a while back), which provides a solution for using an external build script to update the .plist file.
For example:
#!/bin/sh
if [ $# -ne 1 ]; then
echo usage: $0 plist-file
exit 1
fi
plist="$1"
build_date=$(date "+%B %Y")
/usr/libexec/Plistbuddy -c "Set BUILD_DATE \"$build_date\"" "$plist"
and invoke it from the Xcode Build Script using something like:
"${PROJECT_DIR}/tools/set_build_date.sh" "${PROJECT_DIR}/${INFOPLIST_FILE}"
Related
Prelude
I am using App Center for CI of my application with default "Push hook", which rebuilds every time I push to the branch. I have a task to pass an API endpoint as an App Center variable, which is configured in Build Configurations.
Alongside, I have my appcenter-pre-build.sh script, which is placed in the same directory, as .xcworkspace file (as it is noted in official documentation). The script itself looks like this:
#!/usr/bin/env bash
echo "EXECUTING APPCENTER_PRE_BUILD SCRIPT"
if [ -z "$VERSION_CODE_SHIFT" ]
then
echo "You need define the VERSION_CODE_SHIFT variable in App Center"
exit
fi
if [ -z "$ENDPOINT" ]
then
echo "You need define the ENDPOINT variable in App Center"
exit
fi
PLIST_PATH="VideoApp/VideoApp/Info.plist"
VERSION_CODE=$((VERSION_CODE_SHIFT + APPCENTER_BUILD_ID))
APP_CENTER_CURRENT_PLATFORM="ios"
if [ "$APP_CENTER_CURRENT_PLATFORM" == "ios" ]
then
plutil -replace CFBundleVersion -string "$VERSION_CODE" $PLIST_PATH
echo "Updated version code in $PLIST_PATH to new value: $VERSION_CODE"
plutil -replace CFBundleShortVersionString -string "\${MARKETING_VERSION}.$VERSION_CODE" $PLIST_PATH
echo "Updated marketing version in $PLIST_PATH to new value: \${MARKETING_VERSION}.$VERSION_CODE"
plutil -replace HubEndpoint -string "$ENDPOINT" $PLIST_PATH
echo "Updated HubEndpoint in $PLIST_PATH to new value: $ENDPOINT"
fi
So, basically, I pull environment variables from App Center and modify my Info.plist and then use its properties in code to set the API endpoint. Also, as you can see, app's version is being modified in similar fashion.
The Issue
The App Center build eventually fails with the following error:
error: Multiple commands produce '/Users/runner/Library/Developer/Xcode/DerivedData/VideoApp-gpxrsqjtrulyrqamenreayeeatqj/Build/Intermediates.noindex/ArchiveIntermediates/Video-Community/InstallationBuildProductsLocation/Applications/PC365.app/appcenter-pre-build.sh':
1) Target 'Video-Community' (project 'VideoApp') has copy command from '/Users/runner/runners/2.168.2/work/1/s/VideoApp/VideoApp/appcenter-pre-build.sh' to '/Users/runner/Library/Developer/Xcode/DerivedData/VideoApp-gpxrsqjtrulyrqamenreayeeatqj/Build/Intermediates.noindex/ArchiveIntermediates/Video-Community/InstallationBuildProductsLocation/Applications/PC365.app
/appcenter-pre-build.sh'
2) Target 'Video-Community' (project 'VideoApp') has copy command from '/Users/runner/runners/2.168.2/work/1/s/VideoApp/appcenter-pre-build.sh' to '/Users/runner/Library/Developer/Xcode/DerivedData/VideoApp-gpxrsqjtrulyrqamenreayeeatqj/Build/Intermediates.noindex/ArchiveIntermediates/Video-Community/InstallationBuildProductsLocation/Applications/PC365.app
/appcenter-pre-build.sh'
warning: duplicate output file '/Users/runner/Library/Developer/Xcode/DerivedData/VideoApp-gpxrsqjtrulyrqamenreayeeatqj/Build/Intermediates.noindex/ArchiveIntermediates/Video-Community/InstallationBuildProductsLocation/Applications/PC365.app/appcenter-pre-build.sh' on task: CpResource /Users/runner/runners/2.168.2/work/1/s/VideoApp/appcenter-pre-build.sh /Users/runner/Library/Developer/Xcode/DerivedData/VideoApp-gpxrsqjtrulyrqamenreayeeatqj/Build/Intermediates.noindex/ArchiveIntermediates/Video-Community/InstallationBuildProductsLocation/Applications/PC365.app
/appcenter-pre-build.sh (in target 'Video-Community' from project 'VideoApp')
** ARCHIVE FAILED **
##[error]Error: /usr/bin/xcodebuild failed with return code: 65
So it is somehow produces duplicates of this script.
It seems very odd to me, because the script is not assigned to any target and created outside of Xcode.
I guess, the issue was about some kind of script caching. I have removed appcenter-pre-build.sh from the repository, pushed, builded in App Center (this time without errors), then added the script again, pushed and it just worked.
After I migrate my project from swift 3.2 to swift 4 in Xcode 10 I try to archive in Xcode 11 and give me this error:
PhaseScriptExecution Run\ Script
/Users/desarrollo/Library/Developer/Xcode/DerivedData/MyApp-iOS-ewcyzseaubkujucenluznpmduhoo/Build/Intermediates.noindex/ArchiveIntermediates/MyApp-iOS-DEV/IntermediateBuildFilesPath/MyApp-iOS.build/Release-iphoneos/MyApp-iOS-DEV.build/Script-E95AEDE51E54767F00B60429.sh
(in target 'MyApp-iOS-DEV' from project 'MyApp-iOS')
. . .
/Users/desarrollo/Library/Developer/Xcode/DerivedData/MyApp-iOS-ewcyzseaubkujucenluznpmduhoo/Build/Intermediates.noindex/ArchiveIntermediates/MyApp-iOS-DEV/IntermediateBuildFilesPath/MyApp-iOS.build/Release-iphoneos/MyApp-iOS-DEV.build/Script-E95AEDE51E54767F00B60429.sh:
line 5: $(CURRENT_PROJECT_VERSION) + 1: syntax error: operand expected
(error token is "$(CURRENT_PROJECT_VERSION) + 1")
In the error stack I find export CURRENT_PROJECT_VERSION=114
I don't have any script with "$(CURRENT_PROJECT_VERSION) + 1" so I don't know what to do
UPDATE 2:
This causes builds to be canceled! Have a look at S1LENT WARRIOR's answer below, it seems to be working better.
UPDATE 1:
In the latest version of Xcode (Version 11.1) you can do the build number auto increment fairly easily.
Here are the steps:
Go to your target's Build Settings
Search for Versioning System
Set it's value to Apple Generic
Go to your target's Build Phases
Add a new Run Script
Add the following line agvtool next-version -all
Do this for all your targets and their build numbers will all be synced and updated every time you run any of the targets.
Got this answer from here: https://stackoverflow.com/a/58237340/1432355
P.S.: As said in a comment below
Using avgtool in a Run Script Phase causes the build to get cancelled
ORIGINAL:
You didn't do anything wrong I think.
If you go to your info.plist you will see that the build number has been replaced by $(CURRENT_PROJECT_VERSION) (you can find the variable in the Build Settings tab).
I am guessing you are using a script that increments build number automatically and that is causing the issue (I have the same thing on my project right now).
If you remove that script your app should build without this error.
I haven't found a solution yet on how to make the script work with this new $(CURRENT_PROJECT_VERSION) variable. (I will update this answer when I have found the solution)
All the above answers weren't doing the trick by themselves, I had to compute a bunch of them, including the Apple documentation (see references below). So here are the steps I did if it helps someone to have all the steps.
In Info.plist, set:
CFBundleShortVersionString to $(MARKETING_VERSION)
CFBundleVersion to $(CURRENT_PROJECT_VERSION)
In target build settings:
set Versioning System to "Apple Generic"
set Current Project Version to 1 (or whatever version you want)
set Marketing Version to 1.0.0 (or whatever version you want)
In the scheme > Archive:
add a post-action "Run Script Action":
Provide build settings from: your app
in the script:
cd ${PROJECT_DIR} ; xcrun agvtool next-version -all ;
Apple doc mentioned by cuimingda :
https://developer.apple.com/library/archive/qa/qa1827/_index.html
Some of the steps mentioned by moucheg
Just change CFBundleVersion from $(CURRENT_PROJECT_VERSION) to number, in my case is 1000 in Info.plist
<key>CFBundleVersion</key>
<string>1004</string>
Then the shell will be OKey:
buildNumber=$(/usr/libexec/PlistBuddy -c "Print CFBundleVersion" "${PROJECT_DIR}/${INFOPLIST_FILE}")
buildNumber=$(($buildNumber + 1))
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $buildNumber" "${PROJECT_DIR}/${INFOPLIST_FILE}"
Here is the script that worked for me on Xcode 11+
Just add a new Run Script Phase to your Build Phases
Add it below the Link Binary with Libraries phase.
#!/bin/sh
# To make executable, use: chmod u+x Build-Versioning-Scripts/Increment_Build_Number.sh
# to locate your target's info.plist use
# ${PRODUCT_SETTINGS_PATH}
echo "----"
echo "Info.plist for target: ${PRODUCT_SETTINGS_PATH}"
buildNum=$(/usr/libexec/Plistbuddy -c "Print CFBundleVersion" "${PRODUCT_SETTINGS_PATH}")
echo "Current build #: $buildNum"
if [ -z "$buildNum" ]; then
echo "No build number found in $PRODUCT_SETTINGS_PATH"
exit 2
fi
buildNum=$(expr $buildNum + 1)
echo "Build # incremented to: $buildNum"
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $buildNum" "$PRODUCT_SETTINGS_PATH"
echo "----"
exit 0
This script was originally posted here by Alex Zavatone.
Hope this helps
The version and build number (or version and short version) of a Watchkit app and extension have to be set to the same value as the containing app.
I use environment variables to set the apps version in the Info.plist dynamically at build time. That also works fine for the Watchkit extension, but not for the Watchkit app.
The environment variables I use have to be provided in the plist for the main app and extension without ${} (for variable ${VERSION} I set VERSION).
if I do the same for the Watchkit app, it is taking the string itself, not the value. If I provide it with dollar & brackets there is no data in the variable.
Any idea how to set the variables for the Watchkit app?
I use this to update all the targets:
#!/bin/bash
buildNumber=$(/usr/libexec/PlistBuddy -c "Print CFBundleVersion" "$INFOPLIST_FILE")
buildNumber=$(($buildNumber + 1))
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $buildNumber" "$INFOPLIST_FILE"
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $buildNumber" "$SRCROOT/Great WatchKit App/Info.plist"
My CFBundleVersion is the number of commits on my master branch on the git repo.
On my main app target, in Build Phases > + New Run Script Phase I've added this script:
# Set the build number to the count of Git commits
buildNumber=$(git rev-list --count HEAD)
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $buildNumber" "${PROJECT_DIR}/${INFOPLIST_FILE}"
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $buildNumber" "$SRCROOT/app WatchKit Extension/Info.plist"
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $buildNumber" "$SRCROOT/app WatchKit App/Info.plist"
From app WatchKit App the app should be the name of your app, but check the exact path.
You can update the build version of all your targets without a build script. (You can also use this to update the marketing / short build version; in this case ignore changes to CFBundleVersion).
Open your project settings and set CURRENT_PROJECT_VERSION (Current Project Version) to the desired version number. In all targets make sure CURRENT_PROJECT_VERSION is empty (so that its value is inherited from the project). Then in all Info.plist files set CFBundleShortVersionString (Bundle versions string, short) and CFBundleVersion (Bundle version / build version) to $(CURRENT_PROJECT_VERSION).
Optionally, you can distinguish between the build version and the "marketing" version (this is useful if the build version is generated automatically). To do so, in your project settings, set MARKETING_VERSION (Marketing Version) to the desired version number. As before, make sure all targets inherit the value from the project. Finally, in all Info.plist files set CFBundleShortVersionString (Bundle versions string, short) to $(MARKETING_VERSION).
If you want to increment your CFBundleVersion on each build (or to have it reflect your git SHA). Use agvtool as described by dogsgod or see https://developer.apple.com/library/ios/qa/qa1827/_index.html.
stk's answer is right, but I wanted to add my findings as well.
One way to solve the problem is by using agvtools:
Create a new target in OSX > Other > External Build Sytem
Add a run script similar to this one:
#!/bin/bash
#read vesion number from version.txt in project root
VERSION=$(head -n 1 version.txt)
BUILD=`git rev-list $(git rev-parse --abbrev-ref HEAD) | wc -l | awk '{ print $1 }'`
echo "${VERSION} (${BUILD})"
agvtool new-marketing-version ${VERSION}
agvtool new-version -all ${BUILD}
exit 0
I have a version.txt file with only my version number in it (marketing version or short bundle version) that can be easily adjusted by any CI system and use the number of my git SHAs as build number (bundle version)
Adjust the sources for VERSION and BUILD to fit your requirements
Run the scheme that has been created for the new target before your build/archiving.
In case you need to have this as a dependency for your main target - this will fail, as it will stop the execution of the following targets (if somebody knows how to prevent that, I would be thankful for a hint)
But you can still achieve that with a script like the following executed for each of your plists (similar to what stk provided):
#!/bin/sh
#
# usage:
# set-version-in-plist.sh LIST VERSION BUILD
# LIST: Info.plist path & name
# VERSION: version number xxx.xxx.xxx
# BUILD: build number xxxxx
#
# Location of PlistBuddy
PLISTBUDDY="/usr/libexec/PlistBuddy"
${PLISTBUDDY} -c "Set :CFBundleShortVersionString $2" "$1";
${PLISTBUDDY} -c "Set :CFBundleVersion $3" "$1";
Save this script as a file, make it executable (chmod +x SCRIPTNAME)
Then execute it with the mentioned parameter for all your plists
This solution is not so convenient as the agvtools solution, but it should not stop your build when used in a dependency ...
I have a Run Script that I attach to my main app target. It will propagate the WatchKit Extension and the WatchKit app upon building the app.
It is completely reusable. Enjoy!
buildNumber=$(/usr/libexec/PlistBuddy -c "Print CFBundleVersion" "${PROJECT_DIR}/${INFOPLIST_FILE}")
buildNumberDec=$(($buildNumber + 1))
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $buildNumberDec" "${PROJECT_DIR}/${INFOPLIST_FILE}"
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $buildNumberDec" "$SRCROOT/${PRODUCT_NAME} WatchKit Extension/Info.plist"
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $buildNumberDec" "$SRCROOT/${PRODUCT_NAME} WatchKit App/Info.plist"
Well, if it doesn´t work like this, do it with a Run Script Build Phase. Do something like this:
#!/bin/sh
INFOPLIST="${TARGET_BUILD_DIR}/${INFOPLIST_PATH}"
echo "writing to $INFOPLIST"
PLISTCMD="Set :CFBundleVersion $(git rev-list --all|wc -l)"
echo -n "$INFOPLIST" | xargs -0 /usr/libexec/PlistBuddy -c "$PLISTCMD"
I don´t have the right paths for your WatchKit App, so you will have to change that yourself.
If it would be useful to supplement other answers with my own personal experience. These centred around build failure caused by ValidateEmbeddedBinary.
ValidateEmbeddedBinary will fail if the CFBundleVersion is not the same in the embedded WatchKit app and the parent app.
The error looks something like:
(null): error: The value of CFBundleVersion in your WatchKit app's
Info.plist (1234) does not match the value in your companion app's
Info.plist (7931). These values are required to match.
Working in XCode 7.3, the following will first update the parent app's plist. Then it updates the Debug or Release WatchKit app before PBXCp executes to copy it to the parent app directory:
#!/bin/sh
git=`sh /etc/profile; which git`
appBuild=`"$git" rev-list HEAD --count`
appPlistPath="${TARGET_BUILD_DIR}/${INFOPLIST_PATH}"
watchKitPlistPath="${BUILT_PRODUCTS_DIR}/../${CONFIGURATION}-watchos/${PRODUCT_NAME} WatchKit App.app/Info.plist"
echo "Setting App CFBundleVersion $appBuild at info plist path at ${appPlistPath}"
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $appBuild" "${appPlistPath}"
echo "Setting WatchKit App CFBundleVersion $appBuild at ${watchKitPlistPath}"
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $appBuild" "${watchKitPlistPath}"
The above uses git's commit count as CFBundleVersion.
Simple, Easy, No Scripting Needed
Tested with Xcode 13.4.1
This is by far the easiest way to sync build numbers and marketing versions across your targets.
Step 1
Make sure that the project's Current Project Version and Marketing Version are set. This will be the single source of truth for your build number and marketing version. Find these settings by clicking the project in the navigator, clicking the project (above the targets), and typing "versioning" into the filter.
Step 2
Sync Build Number / Project Version (e.g. 123)
In your targets, go to the Build Settings tab and set Current Project Version to $(CURRENT_PROJECT_VERSION).
In your .plist files set Bundle version (same as CFBundleVersion) to $(CURRENT_PROJECT_VERSION).
Sync Marketing Version (e.g. 1.2.3)
In your targets, go to the Build Settings tab and set Marketing Version to $(MARKETING_VERSION)
In your .plist files set Bundle version string (short) (same as CFBundleShortVersionString) to $(MARKETING_VERSION).
Here's a link to my blog post on the topic with more helpful screenshots.
To extend this thread, if someone encounters similar problem as me, hopefully script below will help.
For instance, I have watch target, watch extension, and an app share extension in my project.
I used run phase to update project's plist as suggested, and it works if I build the project, the .plist files are all updated as expected.
However the problem is when you archiving app(let's say all targets have different build number), the info plist in the archived projects was not updated.
After a few times of try out, I found extension's plist files were copied before this run phase, and then the run phase script(updating project's plist) won't help with the archived plist.
So I eventually changed the script to update compiled target's plist, and it works as I expected, I have same build number for all the targets in the application.
Here is how I did it:
add this script to each target's build phase:
infoPlistPath="${TARGET_BUILD_DIR}/${EXECUTABLE_FOLDER_PATH}/Info.plist"
PLISTBUDDY="/usr/libexec/PlistBuddy"
buildNumber=$(git rev-list HEAD | wc -l | tr -d ' ')
$PLISTBUDDY -c "Set :CFBundleVersion $buildNumber" "${infoPlistPath}"
For different target, this EXECUTABLE_FOLDER_PATH was different, and it will update the compiled target's info plist, instead of the project's info plist.
Just a note I checked "Run script only when installing" as well since I only need this to be run for archiving
You can also simply add the same Build Phase to EACH of your targets.
#Update build number with number of git commits if in release mode
if [ ${CONFIGURATION} == "Release" ]; then
buildNumber=$(git rev-list HEAD | wc -l | tr -d ' ')
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $buildNumber" "${PROJECT_DIR}/${INFOPLIST_FILE}"
fi;
So if you have a Watch App, a Watch App Extension, a Widget Extension, or whatever else extension, go to each of their Build Phases, add a New Run Script Phase and paste the above.
I need to adjust my build and version number for my project before build/archiving.
I tried multiple things, but so far to no avail.
I added a target with the script to update the numbers and added that as first dependency to my main target. But because I have multiple dependencies as I have extensions in my app and all dependencies are executed by Xcode in parallel (or at least in random order) this does not work.
I added a pre-action to my scheme with the same result. Xcode is not waiting for my pre-action to complete before continuing with the build (I added a sleep 100 to test).
As I'm altering build numbers it is crucial that the script can complete before anything else is started, but there is also one more side-effect: The build even stops due to the fact that the plist files have been altered while building the related target.
What makes it more difficult is, that I would like to use agvtools to set my version & build number. This obviously starts background processes that are out of my control to alter the plists.
Disclaimer: I have searched for other answers, didn't help.
agvtools just does not work in an Xcode build. It will always stop the build.
What works fine is PlistBuddy, although the setup is not as nice and neat.
I added a Pre-Action to the build in my main scheme to call a new target in my project:
xcodebuild -project "${SRCROOT}/MAIN_APP.xcodeproj" -scheme BuildNumberPreProcess
In the target BuildNumberPreProcess I have a Run Script:
VERSION=$(head -n 1 version.txt)
BUILD=`git rev-list $(git rev-parse --abbrev-ref HEAD) | wc -l | awk '{ print $1 }'`
echo "${VERSION} (${BUILD})"
SCRIPT="${SRCROOT}/CLIENT/Supporting Files/set-version-in-plist.sh"
"${SCRIPT}" "${SRCROOT}/MAIN_APP/Supporting Files/Info.plist" ${VERSION} ${BUILD}
"${SCRIPT}" "${SRCROOT}/EXTENSION/Info.plist" ${VERSION} ${BUILD}
...
set-version-in-plist.h:
#!/bin/sh
# set-version-in-plist.sh
#
# usage:
# set-version-in-plist LIST VERSION BUILD
# LIST: Info.plist path & name
# VERSION: version number xxx.xxx.xxx
# BUILD: build number xxxxx
#
# Location of PlistBuddy
PLISTBUDDY="/usr/libexec/PlistBuddy"
echo "$1: $2 ($3)"
${PLISTBUDDY} -c "Set :CFBundleShortVersionString $2" "$1";
${PLISTBUDDY} -c "Set :CFBundleVersion $3" "$1";
Xcode has command line tools for build/archiving: https://developer.apple.com/library/ios/technotes/tn2339/_index.html
So, you can write shell script that at first runs your script for adjusting build/version number and then runs xcode build/archive as command line tool.
I am trying to figure out how to have the Bundle version number increment automatically in my Xcode 4 project (for ad-hoc and release builds). I found some scripts online that purport to do this but I am unsure of whether to place them in the "Pre-actions" or "Post-actions". I also am unsure what value I should place in the plist; a number that the script will then change or a variable?
All the options that I have tried thus far do not seem to work so any help would be greatly appreciated.
Below is the most recent script I was attempting to use:
conf=${CONFIGURATION}
arch=${ARCHS:0:4}
# Only increase the build number on Device and AdHoc/AppStore build
if [ $conf != "Debug" ] && [ $conf != "Release" ] && [ $arch != "i386" ]
then
buildPlist=${INFOPLIST_FILE}
buildVersion=$(/usr/libexec/PlistBuddy -c "Print CFBuildVersion" $buildPlist)
buildNumber=$(/usr/libexec/PlistBuddy -c "Print CFBuildNumber" $buildPlist)
buildNumber=$(($buildNumber + 1))
/usr/libexec/PlistBuddy -c "Set :CFBuildNumber $buildNumber" $buildPlist
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $buildVersion.$buildNumber" $buildPlist
/usr/libexec/PlistBuddy -c "Set :CFBundleShortVersionString $buildVersion.$buildNumber" $buildPlist
fi
1, Set CFBundleVersion to 1.0.1 or something like x.x.x
2, Add build phases to run shell script autoVersion.sh
3, save below script named autoVersion.sh
#!/bin/sh
# Auto Increment Version Script
# set CFBundleVersion to 1.0.1 first!!!
# the perl regex splits out the last part of a build number (ie: 1.1.1) and increments it by one
# if you have a build number that is more than 3 components, add a '\.\d+' into the first part of the regex.
buildPlist=${INFOPLIST_FILE}
newVersion=`/usr/libexec/PlistBuddy -c "Print CFBundleVersion" "$buildPlist" | /usr/bin/perl -pe 's/(\d+\.\d+\.)(\d+)/$1.($2+1)/eg'`
#echo $newVersion;
/usr/libexec/PListBuddy -c "Set :CFBundleVersion $newVersion" "$buildPlist"
4, run shell: cp autoVersion.sh ~/Documents/ and chmod 777 ~/Documents/autoVersion.sh
5, Build & Enjoy it. :)
perl code from: https://gist.github.com/1436598
You may find the following post helpful:
Auto-Incrementing Build Numbers for Release Builds in Xcodefrom iPhone Development
by Jeff LaMarche
http://iphonedevelopment.blogspot.com/2011/07/auto-incrementing-build-numbers-for.html
The same idea as Alix's answer, but much simpler:
buildNumber=`/bin/date +%Y%m%d%H%M%S`
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $buildNumber" "${PROJECT_DIR}/${INFOPLIST_FILE}"
Add this as a Run Script item on Build Phases on your Target. This has the advantage of being monotonically increasing as well.
This might help you. I am using it in my projects.
https://gist.github.com/alokc83/5207294
#!/bin/sh
# xcode-build-number-generator.sh
# #desc Automaticvally create build number every time using curent day, month and year
# #usage
# 1. Select: your Target in Xcode
# 2. Select: Build Phases Tab
# 3. Select: Add Build Phase -> Add Run Script
# 4. Paste code below in to new "Run Script" section
# 5. Drag the "Run Script" below "Link Binaries With Libraries"
#Credits
# sekati#github for intial direction about automatic versioning
# http://www.codinghorror.com/blog/2007/02/whats-in-a-version-number-anyway.html (For unferstanding the Software Versoining)
#Feel free to leave comment or report issues
MONTH=`date | awk '{print $2}'`
case "$MONTH" in
'Jan' )
MONTHNUMBER=1
;;
'Feb' )
MONTHNUMBER=2
;;
'Mar' )
MONTHNUMBER=3
echo "Month is $MONTHNUMBER"
;;
'Apr' )
MONTHNUMBER=4
;;
'May' )
MONTHNUMBER=5
;;
'Jun' )
MONTHNUMBER=6
;;
'Jul' )
MONTHNUMBER=7
;;
'Aug' )
MONTHNUMBER=8
;;
'Sep' )
MONTHNUMBER=9
;;
'Oct' )
MONTHNUMBER=10
;;
'Nov' )
MONTHNUMBER=11
;;
'Dec' )
MONTHNUMBER=12
;;
esac
DATE=`date | awk '{print $3}'`
echo "Date = $DATE"
YEAR=`date | awk '{print $6}'`
echo "Date = $YEAR"
### only uncomment section below if testing the format in terminal
#echo "BuildNumber1 = $MONTH$DATE$YEAR"
#echo "or BUILD NUMBER = $DATE$MONTH$YEAR"
#echo "or BUILD NUMBER = $MONTHNUMBER$DATE$YEAR Format is |Month Number Date Year|"
#echo "or BUILD NUMBER = $DATE$MONTHNUMBER$YEAR format is |Date MonthNumber Year|"
############################
#### Uncomment only one one style or last one will be in effect
#buildNumber=$MONTH$DATE$YEAR
#buildNumber=$DATE$MONTH$YEAR
buildNumber=$MONTHNUMBER$DATE$YEAR
#buildNumber=$DATE$MONTHNUMBER$YEAR
echo "Final Build number is $buildNumber"
## Below command write buildNumber in the property list
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $buildNumber" "${PROJECT_DIR}/${INFOPLIST_FILE}"
For anyone wanting to integrate version incrementing into a command line build script (perhaps for continuous integration), see the following commands:
# cd into the project folder containing the plist
cd /Users/waitea/iOS/E.ON/iOS/trunk/Eon
# grab the version numbers
major_version=$(grep -C 2 CFBundleVersion App-Info.plist | grep -o '[0-9]\+.[0-9]\+.[0-9]\+')
major_version_min=$(echo $major_version | grep -o '[0-9]\+.[0-9]\+\.')
minor_version=$(echo $major_version | grep -o '[0-9]\+$')
# increment the minor version
increment=`expr $minor_version + 1`
incremented_whole_version="$major_version_min$increment"
# replace the build number in the plist using perl
/usr/bin/perl -p -i -e "s/$major_version/$incremented_whole_version/g" App-Info.plist
That will increment the rightmost number in a x.x.x style version number. Tweak the reg-ex's to alter for your convention.
Took me a while so I thought I'd share to give back to the community!
EDIT - I created a continuous integration system that'll do this for you
https://github.com/adamwaite/XcodeProject
I've found that using tiered xcconfigs helps this problem.
Working on complex builds with apps, libraries, and SDKs you have to be able to coordinate not merely build numbers per project, but build number compatibility.
You can make a build management header that is effectively a text file with build iteration numbers (or versioning info i.e. beta, dev, rel) and import it through the xcconfig import chain per project.
At that point you can have a target build script step that will embed your build/versioning info. This is also best done by putting holding text in your plist and running PlistBuddy on your derived file/built file sections. (This way your source control changes are minimal)
If you can write a build execution script that does the necessary build number twiddling (or better yet, use a system like bamboo which creates the file for you), you can keep that separate from your code. Granted, if you need to do it and keep track, you may have to check in the changed build number to allow it to increment.
I've been able as a result of this to maintain build numbers along the line of:
2.0.3 b34 (3473) Where we have a build number and an SVN checkout build point.
(Please no git hazing, I'm old school)
Pre/Post actions are more for Uber notifications or processes:
Email that the build started/failed/ etc
Copy the done project to the done project server.
Everything else works better as a Build Script.
(And as always: make the script phase call an external script file. DON'T push your script into the project, it's hell on source controlling the project file)
Hope this helps.
FWIW - this is what I'm currently using to increase the build number only for release builds (which includes archiving). Works fine under Xcode 5.1.
Just copy/paste the snippet into a Run script build phase directly in Xcode:
buildnum=$(/usr/libexec/PlistBuddy -c "Print :CFBundleVersion" "$PRODUCT_SETTINGS_PATH")
if [ "$CONFIGURATION" = "Release" ]; then
buildnum=$((buildnum + 1))
echo "Build number updated to $buildnum"
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $buildnum" "$PRODUCT_SETTINGS_PATH"
fi;
If you're using a version system like "x.x.x" you can add this run script. It'll increase the version number (x.x.x+1) every time a new build is made:
if [ "${CONFIGURATION}" != "Debug" ]; then
VERSIONNUM=$(/usr/libexec/PlistBuddy -c "Print CFBundleVersion" "${PROJECT_DIR}/${INFOPLIST_FILE}")
NEWSUBVERSION=`echo $VERSIONNUM | awk -F "." '{print $4}'`
NEWSUBVERSION=$(($NEWSUBVERSION + 1))
NEWVERSIONSTRING=`echo $VERSIONNUM | awk -F "." '{print $1 "." $2 "." $3 ".'$NEWSUBVERSION'" }'`
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $NEWVERSIONSTRING" "${PROJECT_DIR}/${INFOPLIST_FILE}"
fi
I haven't found a great solution for Xcode 10.1. I have modified some scripts to reach the goal. And everything now works fine.
version=$(/usr/libexec/PlistBuddy -c "Print :CFBundleShortVersionString" "${INFOPLIST_FILE}")
build=$(/usr/libexec/PlistBuddy -c "Print :CFBundleVersion" "${INFOPLIST_FILE}")
/usr/libexec/PlistBuddy -c "Set :PreferenceSpecifiers:1:DefaultValue ${version}" "${CODESIGNING_FOLDER_PATH}/Settings.bundle/Root.plist"