Since version 11, Xcode sets my CFBundleVersion
value to $(CURRENT_PROJECT_VERSION)
and my CFBundleShortVersionString
to value $(MARKETING_VERSION)
whenever I enter Version or Build values in the target settings (tab "General").
The actual version and build values that I enter are now stored in the project.pbxproj file. I do not want or like this behaviour, as I use shell scripts to modify the values at buildtime.
I can manually set the correct values in the Info.plist file, but as soon as I change Version or Build numbers in the target settings, the Info.plist file gets changed again by Xcode.
How do I stop Xcode 11 from doing this?
When I modify my build script to change the project file itself, Xcode will immediately cancel the build as soon as the project file is changed.
Don't.
Presumably there is a reason why this behavior changed. If later Xcode features build on this behavior, things get more and more "constructed" down the line.
Instead of trying to bend Xcode, change how the build script retrieves these values:
How to read current app version in Xcode 11 with script
If you need to manipulate the
project.pbxproj
file, it is a Next style plist that is well documented. You can useplistbuddy
which is compatible with this old format. You can also useawk
with more scripting if you have more complex manipulations.If I understand your use case, you could write a script that gets the highest version numbers with
awk
and then updates all lower version numbers it can find in the file withsed
.The road so far
My use case was that:
Settigns.bundle
I used to execute point 1 and 2 as a target build script and point 3 as a custom script on the CI itself.
The new way of storing the version and build within the Xcode build settings were causing issues with the scripts, because they were no longer able to effectively modify the values. At least reading was possible.
Unfortunately i was not able to discover a legit way of preventing Xcode from storing the version and build numbers into the project build settings, however i've managed to create a workaround.
It turns out that when a build or an archive is made, the value written in the
Info.plist
is used. This means that the value is substituted during build time, which does not allow us to modify it during the same build time.I've also tried to modify the project using
xcodeproj
cli, however any changes to the project were causing any builds to stop, so this solution was not working.Eventually, after a lot of different approaches that i tried, i've finally managed find a compromise that was not violating the Xcode's new behavior.
Short Answer:
As a target pre-action, a script is executed which writes the respective values to
CFBundleShortVersionString
andCFBundleVersion
to the target'sInfo.plist
As a source of truth, i use the Xcode build settings to read the values of
MARKETING_VERSION
andCURRENT_PROJECT_VERSION
of the desired target.This way, when you modify the values from the project settings - upon the next build/archive - they will be written to the
Info.plist
, allowing any if your existing scripting logic to continue to work.Detailed Answer
The only way to modify a resource upon a build action is using a
pre-action
script. If you try doing it from a build script - the changes will not take effect immediately and will not be present at the end of the build/archive.In order to add a pre-build action - go to edit scheme.
Then expand the Build and Archive sections. Under
Pre-action
, click theProvide build and settings from
dropdown and select the source of truth target from which you wish to read the values.Add the following script:
The scrip lines do the following:
MARKETING_VERSION
andCURRENT_PROJECT_VERSION
The final step is to write your own sync script that reads the values of the provided
MARKETING_VERSION
andCURRENT_PROJECT_VERSION
to the respective target/s and whenever else you want.In my case the script is the following:
I use shared
Info.plist
andSettings.bundle
between both of my app targets, so i have to update this once.Also i use a notification service extension
BadgeCounter
, which has to have the exact same version and build as the target into which it is embedded. So i update this as well.