Auto-increment semantic build numbers with fastlane.
iOS app build numbers.
The problem
You may be familiar with the CFBundleVersion
settings of your Xcode target.
This can be anything you like really.
While CFBundleShortVersionString
is usually X.Y.Z, there are many options for the CFBundleVersion
, alot of people use auto incrementing numbers like 1 or 100, or 32504. However certain issues may arise from using just integers:
- Do you reset the build number for every version? or does it incrementing.
- If you use Firebase remote config you may be aware of the behaviour that is counter-intuitive where the version actually means
CFBundleVersion
and notCFBundleShortVersionString
(meaning that you'll need to refer to that number and it may not be possible to create a predicate to target desired versions.
The solution
So what is proposed here is that the version or build string, is simply the version string, "X.Y.Z", followed by the build number - "X.Y.Z.B", so that at any given time, just by referring to the number you can discern the release version as well as the build number for test purposes (remember this number is not usually displayed anywhere except under the hood). At the very least, this gets around firebases issue of using the build number and you can match regex such as 3\.[\d]?\.[\d]?
to refer to version 3.x.y.
The implementation
Like many people, we will use fastlane here and give the a practical approach to have this taken care of for you.
The latest_testflight_build_number
utility will give you the latest build number on fastlane and is a good place to start, however simply going +1
here is not enough, bevause we use a "X.Y.Z.B" instead of just "B".
What we desire is to pull the latest build version down, split it into components, increment the last one and push it back. Here's some working code that I have used with success:
# Increment build number - we use syntax major.minor.patch.build
version = get_version_number(target: "<TARGET>")
last_build_number = latest_testflight_build_number(
app_identifier: CredentialsManager::AppfileConfig.try_fetch_value(:app_identifier),
version: version
).to_s
if not last_build_number.include? "."
# Does not exist yet - Append '.0' to the version number
last_build_number = version << ".0"
end
build_components = last_build_number.split('.')
last_component = Integer(build_components[-1]) + 1
build_components[-1] = last_component.to_s
build_version = build_components.join(".")
increment_build_number({
build_number: build_version
})
Conclusion
As you can see, it's only a little more complicated, however it's still handled automatically. Using this same mechanism you could potentially increment the version number automatically if the app has already been released, however for most people that's probably an infrequent occurance for most people (though it is annoying when the build gets rejected because the release stream is closed after release).