多年前,在使用GCC进行编译时,可以预先处理#include .h文件中的以下定义,以便在info.plist中使用:
#define MAJORVERSION 2
#define MINORVERSION 6
#define MAINTVERSION 4
<key>CFBundleShortVersionString</key> <string>MAJORVERSION.MINORVERSION.MAINTVERSION</string>
......这将变成&#34; 2.6.4&#34;。这是有效的,因为GCC支持&#34; -traditional&#34;旗。 (参见Tech Note TN2175 Info.plist files in Xcode Using the C Preprocessor,&#34;消除宏扩展过程中令牌之间的空格&#34;)
然而,快进到2016年和Clang 7.0.2(Xcode 7.2.1)显然不支持&#34; -traditional&#34;或&#34; -traditional-cpp&#34; (或正确支持),产生这个字符串:
"2 . 6 . 4"
(见Bug 12035 - Preprocessor inserts spaces in macro expansions, comment 4)
因为有很多不同的变体(CFBundleShortVersionString,CFBundleVersion,CFBundleGetInfoString),所以解决这个clang问题会很好,并定义一次,并将这些部分连接/串联起来。现在这种做法普遍被接受的模式是什么? (我目前正在MacOS上构建,但相同的模式适用于IOS)
答案 0 :(得分:1)
这是我用来增加构建号的Python脚本,每当检测到源代码更改时,都会更新项目中的一个或多个Info.plist
文件。
它是为解决this question中提出的问题而创建的。我问过一段时间。
您需要在源树中创建如下所示的buildnum.ver
文件:
version 1.0
build 1
(当达到某些项目里程碑时,您需要手动增加version
,但buildnum
会自动递增。
注意 .ver
文件的位置必须位于源树的根目录中(请参阅下面的SourceDir
),因为此脚本将在此处查找已修改的文件目录。如果找到任何内容,则会增加内部版本号。修改意味着上次更新.ver
文件后源文件发生了更改。
然后创建一个新的Xcode目标来运行外部构建工具并运行类似:
tools/bump_buildnum.py SourceDir/buildnum.ver SourceDir/Info.plist
(让它在${PROJECT_DIR}
中运行)
然后使所有实际的Xcode目标依赖于此目标,因此它在构建任何目标之前运行。
#!/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)
答案 1 :(得分:0)
首先,我想澄清每个密钥的用途:
CFBundleShortVersionString
使用semantic versioning描述应用发布版本的字符串。此字符串将显示在App Store说明中。
CFBundleVersion
指定构建版本(已发布或未发布)的字符串。它是一个字符串,但Apple建议使用数字。
CFBundleGetInfoString
似乎已弃用,因为Information Property List Key Reference中已不再列出。
在开发过程中,CFBundleShortVersionString
经常不会更改,我通常会在Xcode中手动设置CFBundleShortVersionString
。我定期更改的唯一字符串是CFBundleVersion
,因为如果CFBundleVersion
未更改,则无法向iTunes Connect / TestFlight提交新版本。
要更改值,我使用带PlistBuddy
的Rake任务将时间戳(年,月,日,小时和分钟)写入CFBundleVersion
:
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。