在Xcode中插入Subversion版本号

25
我想将当前Subversion修订版本号(由svnversion报告)插入我的Xcode项目中。我设法将修订号插入到$PROJECT_DIR中的Info.plist中,但这并不是一个好的解决方案,因为该文件已被版本化。我尝试将修订版插入构建目录中的Info.plist,但在代码签名阶段出现错误(这是一个iPhone应用程序)。
是否有一种简单的方法可以使用某些构建文件将修订版本号插入到应用程序中,以便更改的修订版不会更改版本控制文件?我想也许我可以创建一个临时源文件,链接到其他文件并提供一个函数来获取修订版本号。但我不知道如何做到这一点。
我对其他解决方案(例如agvtool)不太感兴趣。我想要的只是让修订号可用于应用程序,没有太多魔法。

请查看此问题:https://dev59.com/sXVD5IYBdhLWcg3wBm5h - Svante Svenson
那个问题没有明确的答案,而在这种情况下 SVN 关键字替换不是一个好的解决方案 - 他需要一种更新已处理的属性列表文件而不是版本控制的文件的方法。 - Quinn Taylor
您不需要创建一个revision.h文件并将其忽略,您可以使用一个简单的苹果工具直接修改处理过的plist。请参见下面的答案。 - Quinn Taylor
7个回答

37

有一个更简单的解决方案:使用 PlistBuddy,它已包含在Leopard中的 /usr/libexec/PlistBuddy 中。查看我对相关SO问题的回答获取详细信息。

PlistBuddy可以在Xcode内的“运行脚本”构建阶段中使用,并且只能影响处理过的plist文件。将其放置在复制资源阶段之后,甚至无需清理目标即可每次运行。您甚至不需要将值打印到头文件中并使SVN忽略它。

echo -n ${TARGET_BUILD_DIR}/${INFOPLIST_PATH} \
    | xargs -0 /usr/libexec/PlistBuddy -c "Set :CFBundleVersion `svnversion -n`"
假设您在代码签名之前添加了构建阶段,那么您的plist应该使用替换后的值进行签名。

2
不错!这非常接近我想到的解决方案。这种方法唯一的问题是代码签名只在每隔一个构建时进行。这是因为Xcode似乎在执行任何操作之前都会检查依赖项。它假设项目中没有任何更改(不知道shell脚本),因此不需要进行代码签名,并且早早地决定放弃它。这就是为什么我添加了设置结果文件修改时间为1970年的代码。这使得Xcode看到某些内容已过期,必须进行代码签名。 - Nikolai Ruhe
7
你可以将硬编码的 /path/to/Info.plist 替换为 "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}"(包括双引号),这样你就可以在其他项目中重复使用该脚本。 - Nikolai Ruhe
1
除了构建版本号,我还将构建日期和时间放入Info.plist文件中。因此,每次构建时,Info.plist都会更改并需要签名。我还计算并存储存储库路径以跟踪从切换的工作副本构建。 - Nikolai Ruhe
1
"${TARGET_BUILD_DIR}/${INFOPLIST_PATH}"需要用引号括起来吗? - Steven Fisher
2
我的svn版本在升级到Xcode 5后出现了“svn: E200030: sqlite: callback requested query abort”的错误。通过执行svn cleanup命令,问题得以解决。 - Nathan
显示剩余4条评论

10

为了记录,我做了类似于zoul的iPhone应用程序,通过向我的项目添加revision.h文件,然后将以下内容添加为“Run Script”构建阶段:

REV=`/usr/bin/svnversion -nc ${PROJECT_DIR} | /usr/bin/sed -e 's/^[^:]*://;s/[A-Za-z]//'`
echo "#define kRevisionNumber @\"$REV\"" > ${PROJECT_DIR}/revision.h

我采用了这种方式获取简单的修订号,而不是 zoul 解决方案中 svnversion 生成的更详细的字符串。

对于 Mac 应用程序,我基于这篇帖子的方法,并创建了一个 buildnumber.xcconfig 文件。在目标的构建设置中,我将右下角对话框中的 Based On 值更改为 buildnumber.xcconfig。在 Info.plist 中,我编辑了以下行:

<key>CFBundleVersion</key>
<string>${BUILD_NUMBER}</string>
<key>CFBundleShortVersionString</key>
<string>Version 1.0</string>

为了使我的"关于"对话框显示一个类似于版本1.0(1234)的版本字符串,其中1234是Subversion修订号。最后,我创建了一个运行脚本的构建阶段,其中包含以下代码:

REV=`/usr/bin/svnversion -nc ${PROJECT_DIR} | /usr/bin/sed -e 's/^[^:]*://;s/[A-Za-z]//'`
echo "BUILD_NUMBER = $REV" > ${PROJECT_DIR}/buildnumber.xcconfig

这可能不是最简洁的方法,因为它需要在构建新版本前进行清理循环才能使新版本生效于应用程序,但它是有效的。


FYI - PROJECT_DIR 宏定义在我的项目中无法工作,但是这段代码可以:REV=`svnversion -nc | /usr/bin/sed -e 's/^[^:]*://;s/[A-Za-z]//'` echo "#define kRevisionNumber @"$REV"" > ${PROJECT_DIR}/revision.h - snibbe

8
作为 Stack Overflow 的新用户,我无法在 Quinn 的帖子上发表评论,但是如果您正在使用具有多个项目的 SVN 存储库,则需要对他的解决方案进行一些小改动,以使其更加准确。

使用他的方法,返回的 svnversion 号码是整个存储库的最后一次检查,而不一定是您的代码库。这个调整允许更新特定于您的代码库。

REV=`svnversion -nc | /usr/bin/sed -e 's/^[^:]*://;s/[A-Za-z]//'`
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $REV" "${TARGET_BUILD_DIR}"/${INFOPLIST_PATH}

使用-c选项将以“:”的形式收集您代码库中活动分支/标记/主干上完成的最后一次提交,然后切掉不想存储为修订号的位数。
此外,请注意在${TARGET_BUILD_DIR}周围的双引号。这些引号对于将项目放置在名称带有空格的目录结构中的用户是必需的。
希望这能帮助其他人!

8
我在尝试为我的iPhone应用程序做类似的事情时发现了这个页面,认为分享我决定使用的代码可能会有所帮助。我尝试在我的目标信息中设置一个基本版本号(例如0.9.5),然后在其末尾附加我的SVN修订号。我需要将此存储在CFBundleVersion中,以便AdHoc用户可以通过iTunes更新,即使我没有记住在目标信息窗格中修改版本号。这就是为什么我不能使用“revision.h”方法,否则它工作得非常好。这是我最终选择的代码,我将其放置在“复制包资源”构建阶段之后的“运行脚本”阶段:
BASEVERNUM=`/usr/libexec/PlistBuddy -c "Print :CFBundleVersion" "${INFOPLIST_FILE}" | sed 's/,/, /g'`
REV=`svnversion -n`
SVNDATE=`LC_ALL=C svn info | awk '/^Last Changed Date:/ {print $4,$5}'`
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $BASEVERNUM.$REV" "${TARGET_BUILD_DIR}"/${INFOPLIST_PATH}
/usr/libexec/PlistBuddy -c "Set :BuildDateString $SVNDATE" "${TARGET_BUILD_DIR}"/${INFOPLIST_PATH}

它应该将svnversion的结果附加到基本Info.plist中设置的版本号的末尾。这样,您可以在info plist中拥有0.9.5,同时仍然在末尾附加.189修订号,从而得到最终版本号为0.9.5.189。
希望这能帮助其他人!

这正是我想要做的事情;我的唯一小改变是使用来自另一个好答案(George Walters II)的REV=svnversion -nc | /usr/bin/sed -e 's/^[^:]*://;s/[A-Za-z]//' - petert

2
# Xcode auto-versioning script for Subversion
# by Axel Andersson, modified by Daniel Jalkut to add
# "--revision HEAD" to the svn info line, which allows
# the latest revision to always be used.
#
# modified by JM Marino to change only [BUILD] motif
# into CFBundleGetInfoString key.
#
# HOW TO USE IT: just add [BUILD] motif to your Info.plist key :
#       CFBundleVersion
#
# EXAMPLE: version 1.3.0 copyright 2003-2009 by JM Marino
# with [BUILD] into CFBundleVersion key

use strict;

die "$0: Must be run from Xcode" unless $ENV{"BUILT_PRODUCTS_DIR"};

# Get the current subversion revision number and use it to set the CFBundleVersion value
#my $REV = `/usr/local/bin/svnversion -n ./`;
my $REV = `/usr/bin/svnversion -n ./`;
my $INFO = "$ENV{BUILT_PRODUCTS_DIR}/$ENV{WRAPPER_NAME}/Contents/Info.plist";

my $version = $REV;

# (Match the last group of digits without optional letter M | S):
($version =~ m/(\d+)[MS]*$/) && ($version = "" . $1);

die "$0: No Subversion revision found" unless $version;

open(FH, "$INFO") or die "$0: $INFO: $!";
my $info = join("", <FH>);
close(FH);

#$info =~ s/([\t ]+<key>CFBundleVersion<\/key>\n[\t ]+<string>.+)\[BUILD\](<\/string>)/$1$version$2/;
$info =~ s/([\t ]+<key>CFBundleVersion<\/key>\n[\t ]+<string>)\[BUILD\](<\/string>)/$1$version$2/;

open(FH, ">$INFO") or die "$0: $INFO: $!";
print FH $info;
close(FH);

这很好,但如果我没有弄错的话,会改变版本控制的文件。 - zoul

2

由于我无法评论Quinn的答案:

如果您正在使用MacPorts svn客户端,则可能需要包含svnversion命令的完整路径,例如在我的情况下是/opt/local/bin/svnversion。我还添加了svnversion的-c选项。

另外,如果您只对混合修订版的第二个版本号感兴趣,请在调用中添加“cut”命令,如下所示:

echo -n "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}" \
| xargs -0 /usr/libexec/PlistBuddy -c "Set :CFBundleVersion `/opt/local/bin/svnversion -nc | cut -f2 -d:`"

0

另一个版本,用 Apple Script 编写。previousValue 的正则表达式可以更改,目前仅支持 XX.XX.XX 格式的版本(主要版本、次要版本、svn rev)。

/usr/bin/osascript 运行

set myVersion to do shell script "svn info | grep \"^Revision:\""
set myVersion to do shell script "echo " & quoted form of myVersion & "| sed 's/Revision: \\([0-9]\\)/\\1/'" as string

set myFile to do shell script "echo ${BUILT_PRODUCTS_DIR}/${WRAPPER_NAME}/"
set theOutputFolder to myFile as string
set thePListPath to POSIX path of (theOutputFolder & "Info.plist")
tell application "System Events"
   tell property list file thePListPath
      tell contents
         set previousValue to value of property list item "CFBundleVersion"

         set previousValue to do shell script "echo " & quoted form of previousValue & "| sed 's/\\([0-9]*\\.[0-9]*\\)\\(\\.[0-9]*\\)*/\\1/'" as string

         set value of property list item "CFBundleVersion" to (previousValue & "." & myVersion)
      end tell
   end tell
end tell

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接