Is There a Way of Automatically Writing Custom Values to The Bundle's .Plist During a Build Phase

Is there a way of automatically writing custom values to the bundle's .plist during a build phase?

You can edit the Info.plist at build time by taking advantage of the "Pre-actions" options to run a script.

Sample Image

Here's an example script that increments a Key in the Plist called UserDefinedVersionNumber

#!/bin/sh

#Grabs info from plist
plist=$SRCROOT"/"$INFOPLIST_FILE
currentBuild=`/usr/libexec/PlistBuddy -c "Print :UserDefinedVersionNumber" "$plist"`

#And changes it before writing out the plist again
if [ -z "$currentBuild" ]
then
currentBuild=1
/usr/libexec/PlistBuddy -c "Add :UserDefinedVersionNumber string $currentBuild" "$plist"

else
currentBuild=$(($currentBuild + 1));
/usr/libexec/PlistBuddy -c "Set :UserDefinedVersionNumber $currentBuild" "$plist"
fi

You should be able to type the script directly into that little box, but I find that editing and maintaining it can become troublesome, especially for shared scripts.

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

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.

Warning: The Copy Bundle Resources build phase contains this target's Info.plist file

https://developer.apple.com/library/content/qa/qa1649/_index.html

Excerpt:

You are getting this warning because you probably added your Info.plist file to your Copy Bundle Resources build phase as shown in Figure

Sample Image

The INFOPLIST_FILE build setting specifies the name of the Info.plist associated with your target. When building a target, Xcode reads this build setting and copies the referenced Info.plist into your application bundle. Because Xcode automatically processes the Info.plist, you should not add it to your Copy Bundle Resources build phase or make it a target member.

To resolve this warning, select your Info.plist from the Copy Bundle Resource build phase as shown in Figure 1, then click the Remove (–) button to delete it from the phase.

Can you change info.plist inside a Run Script in Xcode's Build Phase?

I assume you're trying to modify the Info.plist (and not a plist.info as I don't know what that is).

It's absolutely possible to create, modify, or delete the Info.plist during the Build Phase. However, you need to do so before the build process needs to make use of Info.plist. The exact timing of this varies, but the earlier the better - I'd recommend doing so right after the Dependencies step.

I have a sample Xcode project that does this for a macOS app and a macOS Command Line Tool. It's considerably more complicated than what you're likely trying to do, but it might be helpful to take a look and see how it's configured.

Better way of incrementing build number?

If I understand your question correctly, you want to modify the Project-Info.plist file, which is a part of the standard project template of Xcode?

The reason I ask this is that Project-Info.plist normally is under version control, and modifying it means that it will be marked as, well, modified.

If that is fine with you, then the following snippet will update the build number and mark the file as modified in the process, where get_build_number is some script (i.e., a placeholder in this example) to get the (possibly incremented) build number that you want to use:

#!/bin/sh

# get_build_number is a placeholder for your script to get the latest build number
build_number = `get_build_number`

/usr/libexec/PlistBuddy -c "Set :CFBundleVersion ${build_number}" ProjDir/Project-Info.plist

PlistBuddy allows you to set any key in a plist file, not just the version number. You can create all the plist files you want, and include them in the resources if needed. They can then be read in from the bundle.

As to your need to show the version in the about pane and other places, you can also look into setting CFBundleGetInfoString and CFBundleShortVersionString.

Simple title output in ios settings bundle

Ok, I had this problem too. The solution (sort of) was to provide a default value field and give that a value. This is actually explicitly stated in the documentation -- Default Value is a required field for the Title property, so if you don't specify it the title won't show in the settings pane. Unfortunately, I can't seem to CHANGE the value once it's set, possibly also as designed -- the documentation also states that it's a read only property. The solution I'm going to try is to just explicitly put the version number in my Root.plist file each time I make a new build. SUPER not ideal, but will work, I think.

EDIT: Check out this post on updating version number in settings bundle

EDIT: Ok, I got this working (thanks to that post, above, and a little hacking around with bash scripts, which I had very little experience with.) Here's the script (which I just wrote inline in a 'Run Script' build phase):

#!/bin/bash

builtInfoPlistPath=${TARGET_BUILD_DIR}/${INFOPLIST_PATH}

#increment the build number
buildNumber=$(/usr/libexec/PlistBuddy -c "Print :CFBundleVersion" "$builtInfoPlistPath")
buildNumber=$(($buildNumber + 1))
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $buildNumber" "$builtInfoPlistPath"

#compose the version number string
versionString=$(/usr/libexec/PlistBuddy -c "Print :CFBundleShortVersionString" "$builtInfoPlistPath")
versionString+=" ("
versionString+=$(/usr/libexec/PlistBuddy -c "Print :CFBundleVersion" "$builtInfoPlistPath")
versionString+=")"

#write the version number string to the settings bundle
#IMPORTANT: this assumes the version number is the first property in the settings bundle!
/usr/libexec/PlistBuddy -c "Set :PreferenceSpecifiers:0:DefaultValue $versionString" "Settings.bundle/Root.plist"

... and that's it! Works like a charm! Hope that helps with your problem, because it solved mine. Only problem now is a slight discrepancy with the build number ...

EDIT: ... which I fixed with vakio's second comment on this post, which instead sets the path to the info.plist to the one which is already processed (before the Run Script phase!)

EDIT: Here's my more up-to-date version, which is in an external file and verifies that some source files have changed before incrementing the build number:

 #!/bin/bash

#note: for simplicity, it's assumed that there's already a bundle version (which is an integer) and a version string. set them in the Summary pane!

#get path to the BUILT .plist, NOT the packaged one! this fixes the off-by-one bug
builtInfoPlistPath=${TARGET_BUILD_DIR}/${INFOPLIST_PATH}
echo "using plist at $builtInfoPlistPath"

modifiedFilesExist=false
#this is the modification date to compare to -- there's a possible bug here, if you edit the built plist directly, for some reason. probably you shouldn't do that anyways.
compModDate=$(stat -f "%m" "$builtInfoPlistPath")

for filename in *
do
modDate=$(stat -f "%m" "$filename")
if [ "$modDate" -gt "$compModDate" ]
then
modifiedFilesExist=true;
echo "found newly modified file: $filename"
break
fi
done

if $modifiedFilesExist
then
echo "A file is new, bumping version"

#increment the build number
buildNumber=$(/usr/libexec/PlistBuddy -c "Print :CFBundleVersion" "$builtInfoPlistPath")
echo "retrieved current build number: $buildNumber"
buildNumber=$(($buildNumber + 1))
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $buildNumber" "$builtInfoPlistPath"
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $buildNumber" "$INFOPLIST_FILE"

#compose the version number string
versionString=$(/usr/libexec/PlistBuddy -c "Print :CFBundleShortVersionString" "$builtInfoPlistPath")
versionString+=" ("
versionString+=$(/usr/libexec/PlistBuddy -c "Print :CFBundleVersion" "$builtInfoPlistPath")
versionString+=")"

#write the version number string to the settings bundle
#IMPORTANT: this assumes the version number is the second property in the settings bundle!
/usr/libexec/PlistBuddy -c "Set :PreferenceSpecifiers:1:DefaultValue $versionString" "Settings.bundle/Root.plist"
else
echo "Version not incremented -- no newly modified files"
fi


Related Topics



Leave a reply



Submit