How do I force Xcode to rebuild the Info.plist file in my project every time I build the project?

30,699

Solution 1

Select 'Edit Scheme', then select 'Build' from the control on the left.

Then, add a Pre-actions step, ensure the scheme in question is selected in the 'Provide build settings from' pulldown and then add this into the edit window below:

rm "${CONFIGURATION_BUILD_DIR}/${INFOPLIST_PATH}"

This will delete the cached version of Info.plist, causing XCode to rebuild it each time you hit build.

Alternatively, if you let Xcode preprocess a template Info.plist file, simply touching the template with

touch ${PROJECT_DIR}/${INFOPLIST_FILE}

works too.

Debugging pre-action scripts

The pre-actions steps do not provide any information when you have made a mistake. You can debug the use of your build variables by adding this line to the script

echo "${CONFIGURATION_BUILD_DIR}/${INFOPLIST_PATH}" > ~/debug.txt

Then check the content of ~/debug.txt to verify that the pre-action script has run and to see if you've used the correct path.

Solution 2

I too have automated setting my version numbers. I created a Run Script Build Phase. The key is to update the target build directory copy of the Info.plist not build directory one. You also need to have your run script after the copy bundle phase. It ok to edit the bundle file directly because is before code signing. You don't want to generate the file thats reinventing the wheel.

Here's my script:

# ---------------------------- IMPORTANT ----------------------------
# You must set GITHash to something like 'Set by build script' in the file
# file '<Project Name>-Info.plist' in the 'Supporting Files' group
# -------------------------------------------------------------------
#
# Get the version number from the tag in git and the number of commits as the build number
#
appVersion=$(git describe --long | cut -f 1 -d "-") 
appBuild=$(git describe --long | cut -f 2 -d "-") 
gitHash=$(git describe --long | cut -f 3 -d "-")
echo "From GIT Version = $appVersion Build = $appBuild"

#
# Set the version info in plist file
#
/usr/libexec/PlistBuddy -c "Set :CFBundleShortVersionString $appVersion" "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}"
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $appBuild" "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}"
/usr/libexec/PlistBuddy -c "Set :GITHash $gitHash" "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}"
echo "Updated ${TARGET_BUILD_DIR}/${INFOPLIST_PATH}"

FYI I also auto set the version and build on the About tab with the following code

NSDictionary *infoDictionary = [[NSBundle mainBundle] infoDictionary];
NSString *appDisplayName = infoDictionary[@"CFBundleDisplayName"];
NSString *majorVersion = infoDictionary[@"CFBundleShortVersionString"];
NSString *minorVersion = infoDictionary[@"CFBundleVersion"];

self.appDescription.text = [NSString stringWithFormat:@"Dirty Dog Software\n%@\nVersion: %@(%@)",
                       appDisplayName, majorVersion, minorVersion];                           

Solution 3

You could try using the touch command to update the timestamp, which I assume is what Xcode uses to determine whether it should be rebuilt, e.g.

$ touch Info.plist

Solution 4

In Xcode 4, you can use a pre build action to touch the info plist.

Note: This is not the same as a run script build phase. A pre build action happens before Xcode checks the info plist, a run script build phase seems to happen after Xcode has already checked the info plist (which is why it only works every other time).

  1. Go to Edit Scheme > Build > Pre-actions
  2. Click the "+" button and choose "New Run Script Action"
  3. Choose your target in the "Provide build settings from" dropdown
  4. Add touch "${SRCROOT}/${INFOPLIST_FILE}" in the script box

Solution 5

Working with Xcode 8.3.2

Inspired by the answer by @LeeH from 2013 I have come up with two solutions for me to rebuild the Info.plist.

Solution 1: Most simple and elegant

The most simple solution is to force Xcode to read your custom variables by touching your targets Info.plist.

Add a build phase, see screenshot below (originally screenshotted for Solution 2), and just add this line:

touch $INFOPLIST_FILE

That is all! Now Xcode should force reload your custom variables into the Info.plist file.

This solution is the same as @lukelutman suggested, but using Build phase. Pre-action script did not work for me.

Solution 2: More complex and hacky

Another solution is to delete the cached Info.plist in the build dir.

I wrote this super simple small bash script

#!/bin/bash
info_plist="$CONFIGURATION_BUILD_DIR/$PRODUCT_NAME.app/Info.plist"
echo "Removing Info.plist from build dir in order to force rebuild of it and reading of correct xcconfig variables, plist path $info_plist"
rm "$info_plist"

I then saved it and called it from build phases for the target. I put it as the first build phase.

enter image description here

Background:

I have three different configurations: Config, Alpha, AppStore and I am using Universal Links, Push Notifications and other stuff that requires the use of an Entitlements file. But I did not want to have three entitlement files, one for each config.

My project already relies heavily on config files (.xcconfig). I actually set up the Entitlement file (MyAppsProductName.entitlements) using custom config variables.

But I wanted to read the same config variables runtime, I figured that I could do it if they would be added to my targets Info.plist. Which worked!

But I noticed that when I changed the values in my .xcconfig file, then the Info.plist file did not change value. I noticed that if I performed a clean build, then the values in the Info.plist got updates according to the values inside the .xcconfig file. Xcode indeed caches the Info.plist file.

So these solutions above fixes this problem. Hope it helps! :)

Discussion

I have no idea if Solution 2 has any advantage over Solution 1... Probably not? Any input anyone?

Share:
30,699
PTTHomps
Author by

PTTHomps

Updated on July 13, 2022

Comments

  • PTTHomps
    PTTHomps almost 2 years

    Apparently the file gets cached, so it only gets built when it gets changed. I have environment variables set to increment my version number though, and such, and update them independently of the plist (in the project build settings, actually). Is there a script that I can use as a script build phase that will force the Info.plist to update? Some other convenient way?