Versioning for iOS & macOS

Article's main picture
  • #iOS
  • #macOS

• 3 min read

Bundle version string, short and Bundle version keys in Info.plist files would always confuse me. However, gone are the days of my bewilderment. Extensive research, in addition to trial and error, have led me to a deeper understanding of this domain. Today, I want to share my story and helpful resources with others who may be struggling with iOS & macOS versioning.

The culprits keys

As we all know, the property list keys in question are CFBundleShortVersionString and CFBundleVersion. For Apple-only-knows-reason, there is just one constant—the kCFBundleVersionKey global variable—and we can only dream about getting another.

Documentation

Bundle version string, short. Let's start with CFBudnleShortVersion documentation. It's really close to Semantic Versioning 2.0.0. The only exception: it doesn't support any pre-release & build metadata (like -alpha.8, -rc.1 or even -rc.2-build.32.45.6). It's crucial that “This key is used throughout the system to identify the version of the bundle.

Bundle version. Let's continue with CFBundleVersion. This is another almost semantic version, but we have a difference: “This key is required by the App Store and is used throughout the system to identify the version of the build.”

The difference. The wonderful Technical Note 2420 explains how those two keys & numbers work together and even more. The tl;dr is that CFBudnleShortVersion is your app version, as we understand it, and CFBundleVersion is a build number for the system to differentiate builds of the same version. But there is one serious gem in this note:

For macOS apps, build numbers must monotonically increase even across different versions. In other words, for macOS apps you cannot use the same build numbers again in different release trains. iOS apps have no such restriction and you can re-use the same build numbers again in different release trains.

Implications

So what we have here is just two triples of integers. If some of you want to make a pile of metadata (long time intervals, commit hashes) in CFBundleVersion (build numbers) with integers, I need to warn you: you have a limit of 18 characters.

Also, we have agvtool that can manage updates of both version & build number. To make it even more spicy, we have new terms as well as places where we can store this information:

  • Marketing version for CFBundleShortVersionString—aka Bundle version string, short—with a corresponding key MARKETING_VERSION in the project build settings.
  • Current project version for CFBundleVersion—aka Bundle version—with a corresponding key CURRENT_PROJECT_VERSION in the project build settings.

There is another article by Apple Technical Q&A QA1827: Automating Version and Build Numbers Using agvtool, which sort of limits our value choice in Current project version:

The value of CURRENT_PROJECT_VERSION must be an integer or a floating point number such as 34.6.

And even if you decide to use a floating point number, there is another bummer with automatic increments:

Running agvtool next-version -all increments your version number to the next highest integer value. For instance, it will update 2 to 3 and 1.3 to 2.

After reading all this, I've settled on using an integer number for CFBundleVersion and don't store build metadata in this key (for release builds).

Roundup

  • It's easy to remember that in string, “short” is for Marketing Version.
  • We can use only eighteen symbols in CFBundleVersion, and this number reminds me of the lyrics from "I'm Eighteen" by Alice Cooper - 'Eighteen I get confused every day'.
  • If agvtool is used, CFBundleVersion should be an integer number (or a floating point number).
  • For macOS apps, both the build number & marketing version should be increased before release.

Resources

Documentation

Apple Developer Documentation - Bundle Configuration

Semantic Versioning 2.0.0

Documentation archive

Technical Note TN2420

Technical Q&A QA1827

More From engineering

Subscribe to our newsletter