CFBundleVersion和CFBundleShortVersionString应该使用什么值?

140

这是我的第一个iOS应用提交,我不想让我的应用被拒绝。

这是从苹果文档中获取的:

CFBundleVersion(字符串 - iOS,OS X)指定包的构建版本号,它标识出包的一次迭代(发布或未发布)。构建版本号应该是由三个非负的、以点分隔的整数组成的字符串,第一个整数大于零。该字符串只能包含数字(0-9)和句点(.)字符。每个整数前导零将被截断并忽略(即1.02.3等同于1.2.3)。该键不可本地化。

CFBundleShortVersionString(字符串 - iOS,OS X)指定软件包的发布版本号,它标识软件包已发布的迭代。发布版本号是由三个以句点分隔的整数组成的字符串。第一个整数表示应用程序的主要修订,例如实现新功能或进行重大更改的修订。第二个整数表示实现较不显著功能的修订。第三个整数表示维护版本。

该键的值与“CFBundleVersion”的值不同,后者标识了应用程序的一次迭代(发布或未发布)。可以通过在InfoPlist.strings文件中包含此键来将此键本地化。

但这似乎有点奇怪。我的解释是将两个值都设置为相同,即:

CFBundleVersion: 1.0.0
CFBundleShortVersionString: 1.0.0

能有人100%确认这就是我应该放的内容吗?


2
根据这个,CFBundleShortVersionString 可以本地化。但如果它必须是由点分隔的三个整数,那么有什么本地化是可能的呢? - Rick
@Rick 我想这意味着你可以将它转换为实际上拥有不同数字,例如阿拉伯语的语言吗? - shiser
2
@shiser 只是挑剔一下,“阿拉伯数字”其实是指我们在西方世界和大多数其他地方使用的数字。但我理解你的意思,有些阿拉伯世界的地区不使用“阿拉伯数字”。https://en.wikipedia.org/wiki/Arabic_numerals - RenniePet
1
这里有另一个答案。https://dev59.com/y2Ei5IYBdhLWcg3wnNPA - AechoLiu
7个回答

156

CFBundleShortVersionString提供了您应用的版本号。每次您发布应用到App Store时,通常会将其递增。这是在应用商店页面的“版本”部分可见的版本。

CFBundleVersion提供了构建号码,用于开发和测试,即“技术”目的。最终用户很少关心构建号码,但在开发过程中,您可能需要知道每个构建中正在开发和修复的内容。这通常在内部发布的每次迭代中进行递增。您可以使用类似Jenkins的持续集成工具来自动递增每个构建的构建号。

版本号和构建号

这两个数字不相互依赖,但为避免混淆,保持它们平行是个好主意。请记住,一旦您的应用程序通过了App Store审核,您需要像Phil和likeTheSky所说的那样递增构建号,无论您是否发布它。

用例:假设您有一个经过充分测试、准备提交的构建。它的版本号为1.0.0,构建号为1.0.0.32。一旦您提交应用程序,您需要将版本更新为1.0.1,构建号更新为1.0.1.0


7
那么,忽略文档中关于CFBundleVersion是“三个”点分隔值的部分是安全的吗? - big_m
我认为这取决于你。如果你不经常发布版本或者不需要通过频繁的测试周期严格遵循错误修复,那么你可以使用三位数字来表示它们。 - Yunus Nedim Mehel
4
是的,您可以使用除了3个数字和标点符号之外的其他值。我在一款iOS运输应用程序中使用了日期时间值,例如“201606070620”。 - Basil Bourque
4
如果您不遵循指南,使用应用内购买可能会遇到问题。请参阅「技术说明2413」。 - DanSkeel
显示剩余2条评论

98

这样来理解: "短版本" (CFBundleShortVersionString) 是公开的版本号,而 "版本" (CFBundleVersion) 则更像是内部版本号,其变化频率可能比公开的 "短版本" 要高得多。个人而言,我会将两者都使用同一版本号,但很多人会在每次构建时更新 "版本" 号。无论如何,通常在向 Apple 发布时更新 "短版本"。你更新 "版本" 的频率取决于你的需求。


20
请注意,捆绑包版本号(CFBundleVersion)必须在数字上超过您先前应用程序的捆绑包版本号,否则在提交到App Store时会出现错误。请参阅https://dev59.com/9W445IYBdhLWcg3wTIfm。 - Phil
6
类似Phil上面所说的,现在如果你重新提交一个失败的(未通过App Store审批的)构建版本,看起来你现在需要在每次提交时提高CFBundleVersion,因此除非你总是完美无误,或者你不介意在成功提交到App Store所需的任何更改时提高你的公共版本号(CFBundleShortVersionString),否则这些数字可能会分歧。 - likethesky

24

rmaddy的回答是正确的。我会再加上两个想法。

第三版号

请注意,在iTunesConnect网站上作为您的应用程序定义的一部分指定的第三版本号。如果该数字与Xcode中的两个数字不同,Apple将向您发出警告。您可以忽略警告,因为它不是致命错误(不是“错误”)。

日期时间作为版本

此外,您不必使用带标点符号的三个数字。对于某些应用程序,这可能是有意义的,其中第一个数字的更改通常表示某种戏剧性更改,通常会影响兼容性。

对于其他应用程序,您可能希望仅使用ISO 8601标准格式样式的日期时间值(YYYYMMDDHHMM)。例如,201606070620。年-月-日-小时-分钟的排序方式会呈现出一个不断增长的数字,由于填充零而始终具有相同的长度,按字母顺序排序时也是按时间顺序排列的。

我已经在运行iOS 7、8和9的发布iOS应用程序上成功使用了这种样式的版本号。

您甚至可以自动生成此值。在项目的目标 > 构建阶段 > 运行脚本面板中:

  1. Shell字段中指定:/bin/sh
  2. 粘贴以下5行脚本。
  3. (可选)选中在构建日志中显示环境变量复选框。
  4. 取消选中仅在安装时运行脚本复选框。

每次执行构建操作时,都会捕获UTC时区中的当前日期时间。脚本中的-u标志使用UTC而不是当前默认时区。通常最好对程序员和系统管理员来说,使用和思考UTC而不是本地时区。

#!/bin/bash
buildNumber=$(date -u "+%Y%m%d%H%M")
/usr/libexec/PlistBuddy -c "Set :CFBundleShortVersionString $buildNumber" "$INFOPLIST_FILE"  # Version number
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $buildNumber" "$INFOPLIST_FILE"  # Build number
echo "DateTime for app version number: $buildNumber"

或者采用混合方式,将传统的1.2.3版本号与日期时间作为构建号。要进行混合,只需在CFBundleShortVersionString行前加上#注释即可。


15
我认为最明智的方案是使用版本号(即CFBundleShortVersionString)作为实际版本号,然后使用构建号(即CFBundleVersion)来表示提交给App Store。因此,除非有任何问题需要重新提交,否则该数字始终为1。对于新版本,如果之前在TestFlight测试或审查中出现问题,我会重置为1。

构建号提供了一种为特定版本的每个提交命名的方法。如上面所述,您为应用程序的特定版本提供的所有构建的集合称为该版本的“发布列车”。对于iOS应用程序,构建号必须在每个发布列车内唯一,但它们不需要在不同的发布列车之间唯一 [我的强调]。也就是说,对于iOS应用程序,如果您想要,可以在不同的发布列车中再次使用相同的构建号。

来自技术笔记TN2420:版本号和构建号

1
很高兴看到有一个答案提供了官方参考,确认了本页面其他答案所提出的解释。 - user2067021

12

我从未看到任何地方讨论的问题是CFBundleVersion中每个字段的最大数字是多少?

通过将应用程序中的CFBundleVersion设置为1.1.1,并查看“lsregister -dump”中版本的十六进制值,我确定第一个字段的最大值为(2 ^ 22)-1或4194303,第二个和第三个字段的最大值为(2 ^ 21)-1或2097151。

这3个字段加起来总共64位。

这对于我们这些基于日期和时间使用CFBundleVersion的人有影响。

我将第一个字段设置为YYYYMMDD。这总是大于允许的最大版本,并且当您安装了多个版本并且正在使用类似于“open-a Appname”之类的命令行时,它会导致不可预测的结果,留给Launch Services决定运行哪个应用程序版本。

请广泛传播此信息。我相信很多人都会因此遇到困难。


你还记得如果添加了第四个字段(1.1.1.20191201)会发生什么,以及你最终使用的是什么吗?我真希望苹果在这里使用与安卓相同的数字值。顺便说一句,感谢你查找这个问题! - spacesuitdiver
我相信限制已经记录在这里(https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html#//apple_ref/doc/uid/20001431-102364),并且比此处提到的更为严格。 - saagarjha

10
截至目前,CFBundleVersion的Apple文档声明如下[我强调]:
建立版本标识了捆绑的迭代。
...
此键是一个由一个到三个用句点分隔的整数组成的机器可读字符串,例如10.14.1。该字符串只能包含数字字符(0-9)和句点。
...
您可以包括更多的整数,但系统会忽略它们。
对于CFBundleShortVersionString [我强调]:
捆绑的发布或版本号。
...
此键是一个用户可见的版本字符串。所需格式是三个用句点分隔的整数,例如10.14.1。该字符串只能包含数字字符(0-9)和句点。
我建议每次构建时自动递增CFBundleVersion(或每次发布到TestFlight),并在更改CFBundleShortVersionString时将其重置为0。
您应该明确计划或设计一种一致的方法来更新CFBundleShortVersionString中可见的用户版本。

2
感谢您提供参考最新的苹果文档的答案。我会给予声望以多次点赞此回答。 - craastad

9
我使用CFBundleVersion来表示内部构建版本,用于CFBundleShortVersionString。我使用TestFlight向我的测试人员提交构建,因此它们之间的差异非常有用。
Apple文档称CFBundleVersion“应该是由3个非负的、以句点分隔的整数组成的字符串”,但实际上它可以有超过3个部分(如上面的答案所示)。我用它来指示我的开发构建,例如,如果我的CFBundleShortVersionString为1.0.0,则我可以使用1.0.0.11作为CFBundleVersion来表示这是我发布1.0.0的第11个构建。
每个提交到应用商店的CFBundleVersion都应该比之前更大,否则你会得到错误ITMS-90478:"无效版本。版本号为“xxx”的构建不能被导入,因为已经关闭了新的构建提交。请选择一个不同的版本号。"
CFBundleShortVersionString只能有3个部分,否则你会得到错误ITMS-90060:"Info.plist文件中键CFBundleShortVersionString 'xxx'的值必须是最多三个非负整数的以句点分隔的列表。"
Basil Bourque提到的第3个数字,即在iTunesConnect上显示的版本号,可能会变得复杂起来。
我使用与CFBundleShortVersionString不同的iTunesConnect编号,因为当我第一次将我的应用程序提交到应用商店时,我们已经进行了多轮内部发布。因此,我使用1.0作为iTunesConnect编号,5.x作为CFBundleShortVersionString。在下一次发布到应用商店时,我提供了一个检查是否有更新版本的功能,并意识到我现在有麻烦了,因为我只能获得iTunesConnect编号(使用http://itunes.apple.com/lookup?bundleId=),所以我需要在将其与CFBundleShortVersionString编号进行比较之前做一些计算。
我试图通过使用iTunesConnect编号作为我的CFBundleShortVersionString来解决这个问题,但是出现了错误ITMS-90062:"此包无效。Info.plist文件中键CFBundleShortVersionString [x.x.x]的值必须包含高于先前批准版本[x.x.x]的版本。"
因此,我建议始终使它们相同。

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