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

喜欢而已 提交于 2019-12-02 20:23:48

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.

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"

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.

stk's answer is right, but I wanted to add my findings as well.

One way to solve the problem is by using agvtools:

Create a new target in OSX > Other > External Build Sytem Add a run script similar to this one:

#!/bin/bash

#read vesion number from version.txt in project root
VERSION=$(head -n 1 version.txt)
BUILD=`git rev-list $(git rev-parse --abbrev-ref HEAD) | wc -l | awk '{ print $1 }'`

echo "${VERSION} (${BUILD})"

agvtool new-marketing-version ${VERSION}
agvtool new-version -all ${BUILD}

exit 0

I have a version.txt file with only my version number in it (marketing version or short bundle version) that can be easily adjusted by any CI system and use the number of my git SHAs as build number (bundle version) Adjust the sources for VERSION and BUILD to fit your requirements

Run the scheme that has been created for the new target before your build/archiving.

In case you need to have this as a dependency for your main target - this will fail, as it will stop the execution of the following targets (if somebody knows how to prevent that, I would be thankful for a hint)

But you can still achieve that with a script like the following executed for each of your plists (similar to what stk provided):

#!/bin/sh
#
# usage:
# set-version-in-plist.sh LIST VERSION BUILD
# LIST:      Info.plist path & name
# VERSION:   version number xxx.xxx.xxx
# BUILD:     build number xxxxx
#

# Location of PlistBuddy
PLISTBUDDY="/usr/libexec/PlistBuddy"

${PLISTBUDDY} -c "Set :CFBundleShortVersionString $2" "$1";
${PLISTBUDDY} -c "Set :CFBundleVersion $3" "$1";

Save this script as a file, make it executable (chmod +x SCRIPTNAME) Then execute it with the mentioned parameter for all your plists

This solution is not so convenient as the agvtools solution, but it should not stop your build when used in a dependency ...

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 sur 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).

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.

If it would be useful to supplement other answers with my own personal experience. These centred around build failure caused by ValidateEmbeddedBinary.

ValidateEmbeddedBinary will fail if the CFBundleVersion is not the same in the embedded WatchKit app and the parent app.

The error looks something like:

(null): error: The value of CFBundleVersion in your WatchKit app's Info.plist (1234) does not match the value in your companion app's Info.plist (7931). These values are required to match.

Working in XCode 7.3, the following will first update the parent app's plist. Then it updates the Debug or Release WatchKit app before PBXCp executes to copy it to the parent app directory:

#!/bin/sh

git=`sh /etc/profile; which git`
appBuild=`"$git" rev-list HEAD --count`

appPlistPath="${TARGET_BUILD_DIR}/${INFOPLIST_PATH}"
watchKitPlistPath="${BUILT_PRODUCTS_DIR}/../${CONFIGURATION}-watchos/${PRODUCT_NAME} WatchKit App.app/Info.plist"

echo "Setting App CFBundleVersion $appBuild at info plist path at ${appPlistPath}"
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $appBuild" "${appPlistPath}"

echo "Setting WatchKit App CFBundleVersion $appBuild at ${watchKitPlistPath}"
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $appBuild" "${watchKitPlistPath}"

The above uses git's commit count as CFBundleVersion.

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"

To extend this thread, if someone encounters similar problem as me, hopefully script below will help.

For instance, I have watch target, watch extension, app share extension in my project.

I used run phase to update project's plist as suggested, and it works if I build the project, the .plist files are all updated as expected.

However the problem is when you archiving app(let's say all targets have different build number), the info plist in the archived projects was not updated. After a few times of try out, I found extension's plist files were copied before this run phase, and then the run phase script(updating project's plist) won't help with the archived plist. So I eventually changed the script to update compiled target's plist, and it works as I expected, I have same build number for all the targets in the application. Here is how I did it: add this script to each target's build phase:

infoPlistPath="${TARGET_BUILD_DIR}/${EXECUTABLE_FOLDER_PATH}/Info.plist"
PLISTBUDDY="/usr/libexec/PlistBuddy"
buildNumber=$(git rev-list HEAD | wc -l | tr -d ' ')
$PLISTBUDDY -c "Set :CFBundleVersion $buildNumber" "${infoPlistPath}"

For different target, this EXECUTABLE_FOLDER_PATH was different, and it will update the compiled target's info plist, instead of the project's info plist. Just a note I checked "Run script only when installing" as well since I only need this to be run for archiving

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!