I received the following email from Apple when I submit an app update:
We have discovered one or more issues with your recent delivery for
"Project". Your delivery was successful, but you may
wish to correct the following issues in your next delivery:
CFBundleVersion Mismatch - The CFBundleVersion value '1' of extension
'Project.app/PlugIns/ProjectTodayExtension.appex' does not
match the CFBundleVersion value '985' of its containing iOS
application 'Project.app'.
CFBundleShortVersionString Mismatch - The CFBundleShortVersionString
value '1.0' of extension 'Project.app/PlugIns/ProjectTodayExtension.appex' does not
match the CFBundleShortVersionString value '2.1.6' of its containing
iOS application 'Project.app'.
After you’ve corrected the issues, you can use Xcode or Application
Loader to upload a new binary to iTunes Connect.
Is there any way of use the same CFBundleVersion and CFBundleShortVersionString in all targets to prevent this?
My solution is:
For CFBundleShortVersionString:
- Add a user-defined constant in your project settings
- Name it $(CF_BUNDLE_SHORT_VERSION_STRING) and set it to your desired value
- Set your version in your targets to $(CF_BUNDLE_SHORT_VERSION_STRING)
- Repeat for all targets. Done!
CFBundleVersion: you could do the same for CFBundleVersion, but somehow I wanted this value to be computed from my GIT repo commit count. I´ve done it like this:
- Add a Pre-action to your main target. You access the shown dialog via Product > Scheme > Edit Scheme
- Add a Post-action to your main target.
- Add a new Command Line Tool target named BundleVersionUpdate and one named BundleVersionRevert
- Navigate to your new BundleVersionUpdate target and add a new Run Script Build Phase
\#!/bin/sh
INFOPLIST="${SRCROOT}/MyApp/MyApp-Info.plist"
INFOPLIST_WKAPP="${SRCROOT}/MyApp-WKApp/Info.plist"
INFOPLIST_WKEXT="${SRCROOT}/MyApp-WKExt/Info.plist"
PLISTCMD="Set :CFBundleVersion $(git rev-list --all|wc -l)"
echo -n "$INFOPLIST"
| xargs -0 /usr/libexec/PlistBuddy -c "$PLISTCMD"
echo -n "$INFOPLIST_WKAPP"
| xargs -0 /usr/libexec/PlistBuddy -c "$PLISTCMD"
echo -n "$INFOPLIST_WKEXT"
| xargs -0 /usr/libexec/PlistBuddy -c "$PLISTCMD"
- Navigate to your new BundleVersionRevert target and add a new Run Script Build Phase and paste this:
\#!/bin/sh
INFOPLIST="${SRCROOT}/MyApp/MyApp-Info.plist"
INFOPLIST_WKAPP="${SRCROOT}/MyApp-WKApp/Info.plist"
INFOPLIST_WKEXT="${SRCROOT}/MyApp-WKExt/Info.plist"
PLISTCMD="Set :CFBundleVersion SCRIPTED"
echo -n "$INFOPLIST"
| xargs -0 /usr/libexec/PlistBuddy -c "$PLISTCMD"
echo -n "$INFOPLIST_WKAPP"
| xargs -0 /usr/libexec/PlistBuddy -c "$PLISTCMD"
echo -n "$INFOPLIST_WKEXT"
| xargs -0 /usr/libexec/PlistBuddy -c "$PLISTCMD"
The scheme actions aren't in source control so it's better to add a build phase into your app's target. Syncing the versions across all targets can be solved with a simple script that can be modified for every target you want synced:
- Add "New Run Script Phase" in "Build Phases" for your app's target
Rename the script to something like "Sync Versions" and drag it above "Compile Sources" (NOTE: Xcode has a bug that may prevent the drag-drop to work. If so, you'll need to manually edit the .pbxproj file so the build phase goes in the right spot
Paste the following script into the shell:
INFOPLIST_MYAPP="${SRCROOT}/MyApp/MyApp-Info.plist"
myAppVersion=$(/usr/libexec/PlistBuddy -c "Print CFBundleShortVersionString" "$INFOPLIST_MYAPP")
myAppBuild=$(/usr/libexec/PlistBuddy -c "Print CFBundleVersion" "$INFOPLIST_MYAPP")
INFOPLIST_SHAREEXT="${SRCROOT}/ShareExtension/Info.plist"
/usr/libexec/PlistBuddy -c "Set :CFBundleShortVersionString $myAppVersion" "$INFOPLIST_SHAREEXT"
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $myAppBuild" "$INFOPLIST_SHAREEXT"
- Build your project as you normally and your share extension's version & build will stay in sync with your main target.
The version of your ProjectTodayExtension.appex have to be the same as your app. example:
Target> General:
Version: 1.0 <- change here
Biuld: 1.0
If the version of your app to get on itunes connect is 2.3, then you must change the version of your TodayExtension to the same version 2.3.
There is a really sweet version management system that Twitch has shared.
Described in this blog post, it is somewhat similar to stk's accepted answer but cleaner and also supports the following:
Ties the build number directly (and reversibly) to the git commit before the build. Go back easily to the exact version built for use with crash report.
Handles version generation through a target dependency, which is easier to share across multiple targets.
Uses C Preprocessor on Info.plist functionality built into Xcode build settings to allow the version numbers to be substituted on the fly, with no modification of the Info.plist file.
It is a little more complex to implement, but it's the best solution I've found, particularly if you have extensions or other targets whose versions must be kept in sync.
Installation Notes: Note the blog does a great job of describing the four shell files, but doesn't really give installation or customization instructions. Here's what I did:
Create a Versions subdirectory at the top level of your project (where the .xcodeproj lives).
Download the four files indicated from the gist link at bottom left of the code samples. Move the four files into your Versions directory.
Using terminal, cd to your Versions directory, then execute the cmd: chmod +x *
to make the shell files executable
Now follow the directions in the blog from the start to create your dependency target.
You probably should customize the scripts a bit. I altered the naming and refactored to move the 4 tools to a separate tools directory that I share across projects. YMMV.
When trying to validate my archive I got an error message CFBundleShortVersionString missing.
To fix the problem I went into Info.plist in the xml code and added CFBundleShortVersionString
new version number
This produced in plist format Bundle versions string, short
This solve my problem