Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I dynamically set my app's build number without dirtying my source tree?

I'm using git-svn and I'm trying to embed my revision number into my iOS app. At the moment, I have a build phase which runs the following script:

SVN_REVISION=$(git svn find-rev HEAD)
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $SVN_REVISION" "$INFOPLIST_FILE"

The problem with this is that, since the repo always contains the previous revision, the script always makes my Info.plist dirty.

Is it possible for me to dynamically set my app's build number without dirtying my source tree?

like image 323
Simon Avatar asked Jan 10 '13 10:01

Simon


People also ask

How do I change my number on iOS build?

Click the Xcode Cloud tab and choose Settings in the sidebar. Click the Build Number tab below Settings. Click the Edit button next to Next Build Number. Enter a new build number and save your changes.

What is CFBundleShortVersionString?

CFBundleShortVersionString gives you the version of your app. It's typically incremented each time you publish your app to the App Store. This is the version that is visible on the "Version" section for the App Store page of your application.

What is build number in iOS?

For an iOS app, the value of the CFBundleVersion key (“Bundle version” in Xcode) is the build number of the app while the value of the CFBundleShortVersionString key (“Bundle versions string, short” in Xcode) is the version number of the app.


1 Answers

1) Add a new target to your project of type "Aggregate", e.g. you may name it "Update Info.plist Prefix Header"; just use that as "Product Name" in the dialog.

2) Add a Run Script build phase to this new target with the following source code:

#!/bin/sh
SVN_REVISION=$(git svn find-rev HEAD)
echo "#define SVN_REVISION $SVN_REVISION" > "$SCRIPT_OUTPUT_FILE_0"


3) Add an output file to your script, name it

$(CONFIGURATION_TEMP_DIR)/InfoPlist.pch


4) Open the Build Phases of your iOS app.

5) Add the aggregate target you created before as dependent target (add it to "Target Dependencies"). This means Xcode will always first build this target before it will build your iOS target.

6) Open the Build Settings of your iOS app.

7) Search for the setting "Info.plist Preprocessor Prefix File" and change it to exactly the same value you used for the output file in step (3).

8) Search for the setting "Preprocess Info.plist File" and make sure it is enabled.

9) Open your current Info.plist file and change the value of CFBundleVersion to SVN_REVISION. Do not use $(SVN_REVISION) or ${SVN_REVISION}; this is no build setting or environment variable replacement, this is a preprocessor replacement, so just use SVN_REVISION.


That's it. Each time you build your iOS app, Xcode first builds the aggregate target, which updates the PCH file, and when it builds your iOS app, it will run the Info.plist file through the C pre-processor (using the PCH file as prefix header) before copying it to your application. The pre-processor will replace SVN_REVISION since it is defined as a macro in your PCH file.

Important Notes

Some people may think it is a better idea to use $(DERIVED_FILE_DIR) instead of $(CONFIGURATION_TEMP_DIR). Well, in theory they are right, yet there is just one problem in practice: The derived file dir is different for every target, while the configuration temp dir is the same (it is only different for every build configuration). When using derived file dir, the PCH file is written to the derived file dir of the aggregate target, yet when building the iOS app, Xcode will search for this file in the derived file dir of the iOS app and thus it won't find the file.

Some people may also think it is a better idea to just add the Run Script phase that updates the prefix header as the first build phase of you iOS app instead of creating a separated target for it (this would also resolve the derived file dir issue mentioned above). Again, nice idea in theory but cannot work in practice: If preprocessing is requested, the Info.plist is preprocessed before the first script phase is even executed, so if the PCH file does not exist already or has not been updated already, either the build terminates with an error or an outdated SVN revision is written to the plist file. That's why you need a separate target for this task that is guaranteed to be build before your actual target is.

like image 109
Mecki Avatar answered Nov 15 '22 09:11

Mecki