如何自动设置Watchkit应用程序目标的版本和内部版本号

Watchkit应用程序和扩展的版本和内部版本(或版本和简短版本)必须设置为与包含应用程序相同的值。

我使用环境variables在构build时dynamic地设置Info.plist的应用程序版本。 这也适用于Watchkit扩展,但不适用于Watchkit应用程序。

我使用的环境variables必须在plist中为主应用程序和扩展提供,而不使用${} (对于variables${VERSION}我设置了VERSION )。
如果我为Watchkit应用程序做同样的事情,它将采取string本身,而不是价值。 如果我提供了美元和括号,variables中没有数据。

任何想法如何设置Watchkit应用程序的variables?

那么,如果没有这样的工作,就用一个Run Script Build Phase 。 做这样的事情:

 #!/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" 

我没有正确的path为您的WatchKit应用程序,所以你将不得不改变这一点。

我用它来更新所有的目标:

 #!/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" 

我的CFBundleVersion是在我的master分支git仓库提交的数量。

在我的主要应用程序目标,在Build Phases > + New Run Script Phase我已经添加了这个脚本:

 # 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" 

app WatchKit Appapp应该是您的应用程序的名称,但检查确切的path。

您可以在不使用构build脚本的情况下更新所有目标的构build版本。 (您也可以使用它来更新营销/短版本;在这种情况下,忽略对CFBundleVersion的更改)。

打开您的项目设置并将CURRENT_PROJECT_VERSION(当前项目版本)设置为所需的版本号。 在所有目标中,使得CURRENT_PROJECT_VERSION为空(以便其值从项目inheritance)。 然后在所有Info.plist文件中将CFBundleShortVersionString(Bundle versions string,short)和CFBundleVersion(Bundle version / build version)设置为$(CURRENT_PROJECT_VERSION)。

如果你想在每个版本上增加你的CFBundleVersion(或者让它反映你的git SHA)。 请按照dogsgod的说明使用agvtool,或者参阅https://developer.apple.com/library/ios/qa/qa1827/_index.html

斯塔克的答案是对的,但我想补充我的发现。

解决问题的一种方法是使用agvtools

OSX中创build一个新的目标> Other> External Build Sytem添加一个类似于这个的运行脚本:

 #!/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 

我有一个version.txt文件,只有我的版本号( 市场版本短包版本 ),可以很容易地由任何CI系统调整,并使用我的git SHA的数量作为内部版本号( 捆绑版本 )调整来源为VERSION和build立适合您的要求

在构build/存档之前运行为新目标创build的scheme。

如果你需要把它作为你的主要目标的一个依赖项,这将会失败,因为它会停止执行下面的目标(如果有人知道如何防止这种情况,我会感激提示)

但是,你仍然可以通过一个像下面这样的脚本来达到这个效果(类似于提供的stk):

 #!/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"; 

将这个脚本保存为一个文件,使其成为可执行文件( chmod +x SCRIPTNAME )然后使用所提到的参数对所有plists执行它

这个解决scheme不像agvtools解决scheme那么方便,但是在依赖中使用时不应该停止构build…

我有一个运行脚本,我附加到我的主要应用程序目标。 它将在构build应用程序时传播WatchKit扩展和WatchKit应用程序。

它是完全可重用的。 请享用!

 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" 

如果以我个人的经验补充其他答案是有用的。 这些以ValidateEmbeddedBinary引起的构build失败为中心。

如果CFBundleVersion在embedded式WatchKit应用程序和父应用程序中不相同,则ValidateEmbeddedBinary将失败。

该错误看起来像这样:

(null):error:WatchKit应用程序的Info.plist(1234)中的CFBundleVersion值与您的伴侣应用程序的Info.plist(7931)中的值不匹配。 这些值需要匹配。

在XCode 7.3中,以下将首先更新父应用程序的plist。 然后在执行PBXCp之前更新Debug或Release WatchKit应用程序,将其复制到父应用程序目录中:

 #!/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}" 

上面使用git的提交计数作为CFBundleVersion

为了扩展这个线程,如果有人遇到类似的问题,希望下面的脚本将有所帮助。

例如,我在我的项目中观看目标,观看扩展,应用程序共享扩展。

我使用运行阶段来更新项目的plistbuild议,如果我build立项目,.plist文件都按预期更新。

然而问题是当你存档应用程序(假设所有目标都有不同的内部版本号),存档项目中的信息列表没有被更新。 经过几次尝试,我发现扩展的plist文件在运行阶段之前被复制,然后运行阶段脚本(更新项目的plist)将无助于归档的plist。 所以我最终改变了脚本来更新编译目标的plist,并且按照我的预期工作,我对应用程序中的所有目标都有相同的内部版本号。 下面是我如何做到的:将这个脚本添加到每个目标的构build阶段:

 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}" 

对于不同的目标,这个EXECUTABLE_FOLDER_PATH是不同的,它将更新编译目标的信息plist,而不是项目的信息plist。 只是一个笔记,我选中了“仅在安装时运行脚本”,因为我只需要运行它就可以进行归档