使用#define和clang为info.plist创build版本号变体?

几年前,在编译GCC时,在#include.h文件中定义的以下内容可以在info.plist中预处理:

#define MAJORVERSION 2 #define MINORVERSION 6 #define MAINTVERSION 4 <key>CFBundleShortVersionString</key> <string>MAJORVERSION.MINORVERSION.MAINTVERSION</string> 

…将变成“2.6.4”。 这是因为海湾合作委员会支持“传统”的国旗。 (请参阅Xcode中的技术说明TN2175 Info.plist文件使用C预处理器 ,在“在macros扩展过程中消除令牌之间的空白”下)

但是,快进到2016和Clang 7.0.2(Xcode 7.2.1)显然不支持“-traditional”或“-traditional-cpp”(或正确支持),产生以下string:

 "2 . 6 . 4" 

(请参阅错误12035 – 预处理程序在macros扩展中插入空格,注释4 )

因为有很多不同的变体(CFBundleShortVersionString,CFBundleVersion,CFBundleGetInfoString),所以最好解决这个叮当问题,并定义一次,然后连接/串联这些部分。 什么是现在这样做的普遍接受的模式? (我目前正在build立在MacOS上,但IOS的工作模式是一样的)

下面是我用来增加内部版本号的Python脚本,无论何时检测到源代码更改,并更新项目中的一个或多个Info.plist文件。

它是为了解决我在这个问题中提出的问题而被创造出来的。

您需要在源代码树中创buildbuildnum.ver文件,如下所示:

 version 1.0 build 1 

(当达到某个项目里程碑时,您将需要手动增加version ,但buildnum会自动增加)。

注意 .ver文件的位置必须位于源代码树的根目录(请参阅下面的SourceDir ),因为此脚本将在此目录中查找已修改的文件。 如果find任何内容,则内部版本号将递增。 .ver文件上次更新后,修改意味着源文件发生更改。

然后创build一个新的Xcode目标来运行一个外部的构build工具,并运行如下所示:

 tools/bump_buildnum.py SourceDir/buildnum.ver SourceDir/Info.plist 

(使其在${PROJECT_DIR}运行)

然后让所有实际的Xcode目标都依赖于这个目标,所以它在它们中的任何一个被构build之前运行。

 #!/usr/bin/env python # # Bump build number in Info.plist files if a source file have changed. # # usage: bump_buildnum.py buildnum.ver Info.plist [ ... Info.plist ] # # andy@trojanfoe.com, 2014. # import sys, os, subprocess, re def read_verfile(name): version = None build = None verfile = open(name, "r") for line in verfile: match = re.match(r"^version\s+(\S+)", line) if match: version = match.group(1).rstrip() match = re.match(r"^build\s+(\S+)", line) if match: build = int(match.group(1).rstrip()) verfile.close() return (version, build) def write_verfile(name, version, build): verfile = open(name, "w") verfile.write("version {0}\n".format(version)) verfile.write("build {0}\n".format(build)) verfile.close() return True def set_plist_version(plistname, version, build): if not os.path.exists(plistname): print("{0} does not exist".format(plistname)) return False plistbuddy = '/usr/libexec/Plistbuddy' if not os.path.exists(plistbuddy): print("{0} does not exist".format(plistbuddy)) return False cmdline = [plistbuddy, "-c", "Set CFBundleShortVersionString {0}".format(version), "-c", "Set CFBundleVersion {0}".format(build), plistname] if subprocess.call(cmdline) != 0: print("Failed to update {0}".format(plistname)) return False print("Updated {0} with v{1} ({2})".format(plistname, version, build)) return True def should_bump(vername, dirname): verstat = os.stat(vername) allnames = [] for dirname, dirnames, filenames in os.walk(dirname): for filename in filenames: allnames.append(os.path.join(dirname, filename)) for filename in allnames: filestat = os.stat(filename) if filestat.st_mtime > verstat.st_mtime: print("{0} is newer than {1}".format(filename, vername)) return True return False def upver(vername): (version, build) = read_verfile(vername) if version == None or build == None: print("Failed to read version/build from {0}".format(vername)) return False # Bump the version number if any files in the same directory as the version file # have changed, including sub-directories. srcdir = os.path.dirname(vername) bump = should_bump(vername, srcdir) if bump: build += 1 print("Incremented to build {0}".format(build)) write_verfile(vername, version, build) print("Written {0}".format(vername)) else: print("Staying at build {0}".format(build)) return (version, build) if __name__ == "__main__": if os.environ.has_key('ACTION') and os.environ['ACTION'] == 'clean': print("{0}: Not running while cleaning".format(sys.argv[0])) sys.exit(0) if len(sys.argv) < 3: print("Usage: {0} buildnum.ver Info.plist [... Info.plist]".format(sys.argv[0])) sys.exit(1) vername = sys.argv[1] (version, build) = upver(vername) if version == None or build == None: sys.exit(2) for i in range(2, len(sys.argv)): plistname = sys.argv[i] set_plist_version(plistname, version, build) sys.exit(0) 

首先,我想澄清每个关键是要做什么:

  • CFBundleShortVersionString

    使用语义版本化描述应用程序发行版本的string。 该string将显示在App Store说明中。

  • CFBundleVersion

    一个string,指定构build版本(已发布或未发布)。 这是一个string,但是Applebuild议使用数字。

  • CFBundleGetInfoString

    似乎不推荐使用,因为它不再列在“ 信息属性列表”中 。

在开发过程中, CFBundleShortVersionString不会经常更改,我通常在Xcode中手动设置CFBundleShortVersionString 。 我经常更改的唯一string是CFBundleVersion ,因为如果CFBundleVersion没有更改,则无法将新版本提交到iTunes Connect / TestFlight。

要改变这个值,我使用一个带PlistBuddy的Rake任务来为PlistBuddy写一个时间戳(年,月,日,小时和分钟):

 desc "Bump bundle version" task :bump_bundle_version do bundle_version = Time.now.strftime "%Y%m%d%H%M" sh %Q{/usr/libexec/PlistBuddy -c "Set CFBundleVersion #{bundle_version}" "DemoApp/DemoApp-Info.plist"} end 

如果您需要自动化CFBundleShortVersionString ,则可以使用PlistBuddy。