How to automatically set the version and build number of a Watchkit app target

14,767

Solution 1

Well, if it doesn´t work like this, do it with a Run Script Build Phase. Do something like this:

#!/bin/sh
INFOPLIST="${TARGET_BUILD_DIR}/${INFOPLIST_PATH}"
echo "writing to $INFOPLIST"
PLISTCMD="Set :CFBundleVersion $(git rev-list --all|wc -l)"
echo -n "$INFOPLIST" | xargs -0 /usr/libexec/PlistBuddy -c "$PLISTCMD"

I don´t have the right paths for your WatchKit App, so you will have to change that yourself.

Solution 2

I use this to update all the targets:

#!/bin/bash
buildNumber=$(/usr/libexec/PlistBuddy -c "Print CFBundleVersion" "$INFOPLIST_FILE")
buildNumber=$(($buildNumber + 1))
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $buildNumber" "$INFOPLIST_FILE"
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $buildNumber" "$SRCROOT/Great WatchKit App/Info.plist"

Solution 3

My CFBundleVersion is the number of commits on my master branch on the git repo.

On my main app target, in Build Phases > + New Run Script Phase I've added this script:

# Set the build number to the count of Git commits
buildNumber=$(git rev-list --count HEAD)
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $buildNumber" "${PROJECT_DIR}/${INFOPLIST_FILE}"
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $buildNumber" "$SRCROOT/app WatchKit Extension/Info.plist"
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $buildNumber" "$SRCROOT/app WatchKit App/Info.plist"

From app WatchKit App the app should be the name of your app, but check the exact path.

Solution 4

You can update the build version of all your targets without a build script. (You can also use this to update the marketing / short build version; in this case ignore changes to CFBundleVersion).

Open your project settings and set CURRENT_PROJECT_VERSION (Current Project Version) to the desired version number. In all targets make sure CURRENT_PROJECT_VERSION is empty (so that its value is inherited from the project). Then in all Info.plist files set CFBundleShortVersionString (Bundle versions string, short) and CFBundleVersion (Bundle version / build version) to $(CURRENT_PROJECT_VERSION).

Optionally, you can distinguish between the build version and the "marketing" version (this is useful if the build version is generated automatically). To do so, in your project settings, set MARKETING_VERSION (Marketing Version) to the desired version number. As before, make sure all targets inherit the value from the project. Finally, in all Info.plist files set CFBundleShortVersionString (Bundle versions string, short) to $(MARKETING_VERSION).

If you want to increment your CFBundleVersion on each build (or to have it reflect your git SHA). Use agvtool as described by dogsgod or see https://developer.apple.com/library/ios/qa/qa1827/_index.html.

Solution 5

I have a Run Script that I attach to my main app target. It will propagate the WatchKit Extension and the WatchKit app upon building the app.

It is completely reusable. Enjoy!

buildNumber=$(/usr/libexec/PlistBuddy -c "Print CFBundleVersion" "${PROJECT_DIR}/${INFOPLIST_FILE}")

buildNumberDec=$(($buildNumber + 1))

/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $buildNumberDec" "${PROJECT_DIR}/${INFOPLIST_FILE}"
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $buildNumberDec" "$SRCROOT/${PRODUCT_NAME} WatchKit Extension/Info.plist"
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $buildNumberDec" "$SRCROOT/${PRODUCT_NAME} WatchKit App/Info.plist"
Share:
14,767
dogsgod
Author by

dogsgod

Updated on June 04, 2022

Comments

  • dogsgod
    dogsgod almost 2 years

    The version and build number (or version and short version) of a Watchkit app and extension have to be set to the same value as the containing app.

    I use environment variables to set the apps version in the Info.plist dynamically at build time. That also works fine for the Watchkit extension, but not for the Watchkit app.

    The environment variables I use have to be provided in the plist for the main app and extension without ${} (for variable ${VERSION} I set VERSION).
    if I do the same for the Watchkit app, it is taking the string itself, not the value. If I provide it with dollar & brackets there is no data in the variable.

    Any idea how to set the variables for the Watchkit app?

  • dogsgod
    dogsgod about 9 years
    Already found that solution, but I prefer agvtool - it sets all plists in one go
  • stk
    stk about 9 years
    Nice! Can you share the solution?
  • dogsgod
    dogsgod about 9 years
    planned to do so - actually that's what you commented on yesterday, when I misunderstood some question ...
  • Moshe
    Moshe about 9 years
    Is there a way to generalize the last line so it works in any app?
  • dogsgod
    dogsgod about 9 years
    sure. see my answer below (or above if I get voted :))
  • Parrots
    Parrots about 9 years
    That won't work as you can't (as of Xcode 6.3) add any kind of build phases to a watchkit app, only the watchkit extension can have build phases.
  • stk
    stk about 9 years
    That´s right, my answer was related to Xcode 6.2, where the WatchKit App didn´t neither had the Build Settings tab nor had the check for same CFBundleVersion.
  • stk
    stk about 9 years
    This is nearly an exact duplicate of Lucien.
  • stk
    stk about 9 years
    At which position in your Build Phases did you add this? Before 'Compile Sources'?
  • dogsgod
    dogsgod about 9 years
    See my answer for a working solution. It's working great with all versions including 6.3.1
  • Lucien
    Lucien about 9 years
    After, it's the last one. I've marked Run script only when installing so it will increment only on archives. Didn't like to pollute every commit with a change on 3 plists.
  • stk
    stk about 9 years
    Yeah, agvtool is good, but I don´t want to use a second target for the deployment process. And for the manual setting with PListBuddy, I´m struggling with the timing and which-file-is-read-or-written-before-what-else.
  • Sam Bantner
    Sam Bantner about 9 years
    Is anything original anymore?!? :) It's just pulling the Product Name to allow for a more re-usable experience.
  • stk
    stk about 9 years
    I´ve managed to get it working now, will update my answer in the next days.
  • dogsgod
    dogsgod about 9 years
    It's not only a duplicate of other answers, it's also highly redundant and does not add anything new
  • Shaolo
    Shaolo over 8 years
    Instead of using this as a build phase, you could put it in the hooks directory of your git/svn repo.
  • ShimSham
    ShimSham about 8 years
    I had to add this run script just after the Copy Bundle Resources, otherwise I got a failed build with complaining on non matching version numbers (however after the build the version numbers where all identical).
  • ShimSham
    ShimSham about 8 years
    I had to add this run script just after the Copy Bundle Resources, otherwise I got a failed build with complaining on non matching version numbers (however after the build the version numbers where all identical).
  • dogsgod
    dogsgod almost 8 years
    if you have that level of access, that might work - but I don't
  • Christian
    Christian almost 8 years
    for me this is the correct answer, as all scripting is not needed and it seems this is what Apple thought it should be like.
  • blwinters
    blwinters over 6 years
    For my configuration, I needed to replace "${PROJECT_DIR}/${INFOPLIST_FILE}" with "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}".
  • blwinters
    blwinters over 6 years
    Thanks for this. It's helpful to know how to define the watchKitPlistPath within ${BUILT_PRODUCTS_DIR}, since that is not tracked by Git.
  • blwinters
    blwinters over 6 years
    If you change the build number for the plist files within BUILT_PRODUCTS_DIR, then they won't be tracked by Git in your main project directory, as explained here. For example: iOS App: "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", Watch app: "${BUILT_PRODUCTS_DIR}/../${CONFIGURATION}-watchos/MyApp_Wat‌​ch.app/Info.plist" and Watch extension: "${BUILT_PRODUCTS_DIR}/../${CONFIGURATION}-watchos/MyApp_Wat‌​ch_Extension.appex/I‌​nfo.plist".
  • Steven
    Steven almost 4 years
    Hi @stk, I use Svn to commit my version and not git, how can I use ur script for my extension? Thanks
  • Steven
    Steven almost 4 years
    In last line Instead of Great WatchKit App, should I write the name of my main app or the name of extension.
  • Steven
    Steven almost 4 years
    Should I add this script to my extension or also to may main app? If I add only to my extension is it going to work? Since in my main app has many script...
  • Steven
    Steven almost 4 years
    Hi @dogsgod, I use svn and in my main app I use script which get the version number from svn. I see in ur example that used for git, is there away just to use in my extension that can inherit directly from main app plist, the version .
  • Dmitry
    Dmitry almost 3 years
    For the CFBundleShortVersionString (Bundle versions string, short) I would use $(MARKETING_VERSION)
  • Trev14
    Trev14 almost 2 years
    I agree this should be the accepted answer. Scripting shouldn't be necessary & creates more complexity than we need to deal with. Thanks for the simple solution.