24

I am trying to do the following:

  1. During the build phase, open a plain text file and read the text
  2. Change the value of a property in info.plist to the value obtained in step 1.

Can I write a shell script for this?

It will be great if someone can guide me to achieve this.

Wyetro
  • 8,439
  • 9
  • 46
  • 64
Mithin
  • 961
  • 1
  • 11
  • 37

4 Answers4

25

Probably the simplest way is to use PlistBuddy. I have a Run Script phase that looks like this:

BUILD_NUMBER=`git rev-list HEAD --count`
INFO_PLIST="$BUILT_PRODUCTS_DIR/$INFOPLIST_PATH"
if [ -f "$INFO_PLIST" ] ; then
    oldversion=`/usr/libexec/PlistBuddy -c "Print :CFBundleVersion" "$INFO_PLIST"`
fi
if [ "$BUILD_NUMBER" != "$oldversion" ] ; then
    /usr/libexec/PlistBuddy -c "Set :CFBundleVersion $BUILD_NUMBER" "$INFO_PLIST"
fi

(Note that starting with Xcode 6, you have to run this after the Copy Bundle Resources phase, because Info.plist isn't copied to the target location until then and PlistBuddy would fail.)

Edit 01/17: Updated to avoid unnecessary copying or signing of targets. You don’t want to touch Info.plist unless something really changes, otherwise Xcode will treat it (and thus the target) as modified. Checking previous value CFBundleVersion can significantly speed up builds — it saved me several seconds on noop build.

netdigger
  • 3,659
  • 3
  • 26
  • 49
Václav Slavík
  • 6,445
  • 2
  • 28
  • 25
  • 1
    It took me forever to figure out why my script worked for regular builds but failed on archive builds. It has to run after Copy Bundle Resources. Thank you! – Sami Samhuri Jan 21 '16 at 06:47
  • 1
    You don't need plist buddy, you can set plist values using the standard `defaults write` command with a custom plist path –  Jan 20 '21 at 12:29
13

Yes you can. I would do it in three steps:

  1. Write a shell script that is run before the first build-phase. Let this script set an environment variable.
  2. Enable "Expand Build Settings in Info.plist" for you project.
  3. Use the environment variable in the plist file like ${MY_COOL_SETTING}.
karim
  • 15,408
  • 7
  • 58
  • 96
PeyloW
  • 36,742
  • 12
  • 80
  • 99
  • 1
    Thanks! But how can I open a file and read the text from it during this phase? – Mithin Aug 02 '11 at 15:35
  • @Mithin - Completely depends on the language you write the shell script in. – PeyloW Aug 02 '11 at 15:58
  • 2
    What if the key is a boolean? It won't accept the environment variable name placeholders then. –  Sep 08 '12 at 13:26
  • 3
    Any guidance as to how I let a script set up an environment variable? Also, isn't it supposed to be ${MY_COOL_SETTING}? – Scott Berrevoets Nov 27 '12 at 18:42
  • 2
    can anybody confirm this works with the most recent Xcode 4? Does not seem to work for me (and does indeed sound like it should not, it's a subshell after all) – Ahti Aug 24 '13 at 15:00
  • 1
    @Ahti No, it doesn't, nor (as you say) should it. See below for a better solution. – Václav Slavík Oct 14 '14 at 06:32
  • 10
    I do not understand how this is accepted answer. How do you export environment variable from script phase. (step #1) – Shchvova May 21 '17 at 22:08
7

@PeyloW offers one way to do it. The other way to do it is to add a Run Script build step. In that step you can rewrite your Info.plist anyway you like. I do this all the time to set the svnversion.

I recommend putting your script in a file, and then putting . myscript.sh in the Run Script phase. This is easier to understand and maintain than putting the entire script directly in Xcode.

Rob Napier
  • 286,113
  • 34
  • 456
  • 610
  • 2
    +1 for putting the script in a separate file. I used to rewrite the plist file as well. But doing so tend to make unnecessary revisions for the plist file in source control. So I changed to the env-variable solution. – PeyloW Aug 02 '11 at 13:55
  • The env-variable solution is nice, and if I build another versioning script, I may switch to that approach for simplicity. The script is more flexible. – Rob Napier Aug 02 '11 at 13:59
4

I have a script file that puts a build number into a field in my info.plist. I put some place holder text in the info.plist in project and then the script just replaces it. It only increments the build number on release builds. On development builds it just says they are a development build.

   if [ "$BUILD_STYLE" = "Release" ] 
   then
   if [ ! -f build-number ]; then
        echo 0 > build-number
   else
        expr  `cat build-number` + 1 > build-number.new
        mv build-number.new build-number
   fi

    perl -pi -e s/BUILD_NUMBER_PLACEHOLDER/`cat build-number`/ $BUILT_PRODUCTS_DIR/$PRODUCT_NAME.app/Contents/Info.plist
   else
    perl -pi -e s/BUILD_NUMBER_PLACEHOLDER/`echo Development`/ $BUILT_PRODUCTS_DIR/$PRODUCT_NAME.app/Contents/Info.plist
   fi
Ron Davis
  • 1,259
  • 11
  • 13