Xcode中的版本与构建


660

我有一个使用Xcode 3开发的应用程序,最近开始使用Xcode 4进行编辑。在目标摘要中,我具有iOS应用程序目标表单,其中包含以下字段:标识符,版本,内部版本,设备和部署目标。版本字段为空白,构建字段为3.4.0(与我仍使用Xcode 3进行编辑时的应用程序版本匹配)。

我的问题是:

  1. 版本和构建字段之间有什么区别?

  2. 升级到Xcode 4后,版本字段为何空白?


一方面,我认为Xcode Organizer存档列表中显示的是内部版本号。除此之外,我不确定它的用途。
丹尼尔·迪基森

Answers:


1224

苹果有点重新布置了这些领域。

展望未来,如果您在“应用程序目标”的“信息”选项卡上查找,则应使用“捆绑版本字符串,短”作为版本(例如3.4.0),并使用“捆绑版本”作为构建(例如500或1A500) )。如果您没有同时看到它们,则可以添加它们。这些将映射到“摘要”选项卡上的正确的“版本”和“构建”文本框;它们是相同的值。

查看“信息”选项卡时,如果右键单击并选择“ 显示原始键/值”,您将看到实际名称为CFBundleShortVersionString(版本)和CFBundleVersion(构建)。

通常使用该版本,就像您在Xcode 3上使用它的方式一样。我不确定您在哪个级别上询问版本/内部版本的差异,因此我会从哲学上回答它。

有各种各样的方案,但是一种流行的方案是:

{MajorVersion}。{MinorVersion}。{修订版}

  • 重大版本 -重大更改,重新设计和功能更改
  • 次版本 -次要改进,功能增加
  • 修订版 -漏洞修复的补丁号

然后,单独使用内部版本来指示发行版或整个产品生命周期的内部版本总数。

许多开发人员将内部版本号从0开始,并且每次他们构建时,他们都会将内部版本号增加1,并永远增加。在我的项目中,我有一个脚本,该脚本在每次构建时都会自动增加构建号。请参阅下面的说明。

  • 1.0.0版可能是版本542。花了542个版本才能达到1.0.0版。
  • 版本1.0.1可能是内部版本578。
  • 1.1.0版可能是内部版本694。
  • 2.0.0版可能是内部版本949。

其他开发人员(包括Apple)的内部版本号由主要版本+次要版本+该版本的内部版本号组成。这些是实际的软件版本号,而不是用于营销的值。

如果转到Xcode菜单> 关于Xcode,则会看到版本号和内部版本号。如果您点击“ 更多信息...”按钮,将会看到很多不同的版本。由于在Xcode 5中删除了“ 更多信息...”按钮,因此也可以从“ 系统信息”应用程序的“ 软件”>“开发人员”部分获得此信息,方法是打开Apple菜单>“ 关于本机” >“ 系统报告...”

例如,Xcode 4.2(4C139)。市场营销版本4.2是内部版本主要版本4,内部版本次要版本C和内部版本号139。下一个版本(可能为4.3)可能是内部版本4D,内部版本号将从0开始并从此处递增。

iPhone模拟器的版本号/内部版本号与iPhone,Mac等相同。

  • 3.2:(7W367a)
  • 4.0:(8A400)
  • 4.1:(8B117)
  • 4.2:(8C134)
  • 4.3:(8H7)

更新:根据要求,以下是创建脚本的步骤,该脚本每次在Xcode中构建应用程序时运行,以读取内部版本号,增加内部版本号并将其写回到应用程序{App}-Info.plist文件中。如果要将版本/内部版本号写入Settings.bundle/Root*.plist文件,则有其他可选步骤。

这是从此处的操作方法文章扩展而来的。

在Xcode 4.2-5.0中:

  1. 加载您的Xcode项目。
  2. 在左侧窗格中,在层次结构的最顶部单击您的项目。这将加载项目设置编辑器。
  3. 在中央窗口窗格的左侧,在“ 目标”标题下单击您的应用程序。您将需要为每个项目目标配置此设置。
  4. 选择构建阶段选项卡。
    • 在Xcode 4中,单击右下角的Add Build Phase按钮,然后选择Add Run Script
    • 在Xcode 5中,选择编辑器菜单> 添加构建阶段 > 添加运行脚本构建阶段
  5. 拖放新的“运行脚本”阶段,以将其移至“ 复制捆绑资源”阶段之前(此时app-info.plist文件将与您的应用捆绑在一起)。
  6. 在新的“运行脚本”阶段,设置Shell/bin/bash
  7. 将以下内容复制并粘贴到脚本区域中以获取整数内部版本号:

    buildNumber=$(/usr/libexec/PlistBuddy -c "Print CFBundleVersion" "$INFOPLIST_FILE")
    buildNumber=$(($buildNumber + 1))
    /usr/libexec/PlistBuddy -c "Set :CFBundleVersion $buildNumber" "$INFOPLIST_FILE"

    正如@Bdebeez所指出的,Apple通用版本控制工具agvtool)也可用。如果您更喜欢使用它,那么首先要进行几件事更改:

    • 选择构建设置选项卡。
    • 在“ 版本控制”部分下,将“ 当前项目版本”设置为要使用的初始内部版本号,例如1
    • 返回“ 构建阶段”选项卡上,将“运行脚本”阶段拖放到“ 复制捆绑资源阶段之后,以避免在尝试构建和更新包含内部版本号的源文件时出现竞争情况。

    请注意,使用该agvtool方法,您仍可能会定期获得失败/取消的构建,而不会出现任何错误。出于这个原因,我不建议agvtool与此脚本一起使用。

    但是,在运行脚本阶段,您可以使用以下脚本:

    "${DEVELOPER_BIN_DIR}/agvtool" next-version -all

    next-version参数增加内部版本号(bump也是同一事物的别名),并使用新的内部版本号进行-all更新Info.plist

  8. 并且,如果您在其中显示“版本”和“构建”的“设置”捆绑包中,则可以在脚本末尾添加以下内容以更新版本和构建。注意:更改PreferenceSpecifiers值以匹配您的设置。PreferenceSpecifiers:2意味着要查看PreferenceSpecifiersplist文件中数组下的索引2处的项,因此对于基于0的索引,这是数组中的第3个首选项设置。

    productVersion=$(/usr/libexec/PlistBuddy -c "Print CFBundleShortVersionString" "$INFOPLIST_FILE")
    /usr/libexec/PlistBuddy -c "Set PreferenceSpecifiers:2:DefaultValue $buildNumber" Settings.bundle/Root.plist
    /usr/libexec/PlistBuddy -c "Set PreferenceSpecifiers:1:DefaultValue $productVersion" Settings.bundle/Root.plist

    如果您使用的是agvtool代替Info.plist直接阅读的内容,则可以在脚本中添加以下内容:

    buildNumber=$("${DEVELOPER_BIN_DIR}/agvtool" what-version -terse)
    productVersion=$("${DEVELOPER_BIN_DIR}/agvtool" what-marketing-version -terse1)
    /usr/libexec/PlistBuddy -c "Set PreferenceSpecifiers:2:DefaultValue $buildNumber" Settings.bundle/Root.plist
    /usr/libexec/PlistBuddy -c "Set PreferenceSpecifiers:1:DefaultValue $productVersion" Settings.bundle/Root.plist
  9. 如果您有适用于iPad和iPhone的通用应用程序,则还可以设置iPhone文件的设置:

    /usr/libexec/PlistBuddy -c "Set PreferenceSpecifiers:2:DefaultValue $buildNumber" Settings.bundle/Root~iphone.plist    
    /usr/libexec/PlistBuddy -c "Set PreferenceSpecifiers:1:DefaultValue $productVersion" Settings.bundle/Root~iphone.plist

17
“在我的项目中,我有一个脚本,该脚本在每次构建时都会自动增加构建号”-您可以分享如何做吗?感谢您提供详细信息和原始问题。
Zsolt

2
@Andrews-我用构建脚本的详细信息更新了答案。
nekno 2011年

9
要增加十六进制数字,您可以使用buildNumber=$(/usr/libexec/PlistBuddy -c "Print CFBundleVersion" "$INFOPLIST_FILE") dec=$((0x$buildNumber)) buildNumber=$(($dec + 1)) hex=$(printf "%X" $buildNumber) /usr/libexec/PlistBuddy -c "Set :CFBundleVersion $hex" "$INFOPLIST_FILE"
Alon Amir,

8
简而言之:AppStore中不允许使用十六进制。
Nicolas Miari

3
(Xcode 5用户)您可能需要将步骤5更改为:“从菜单栏中,选择
Editor-

72

(请留在这里供我自己参考。)这将显示您在Xcode目标中看到的“版本”和“构建”字段的版本和构建:

- (NSString*) version {
    NSString *version = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"];
    NSString *build = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"];
    return [NSString stringWithFormat:@"%@ build %@", version, build];
}

在斯威夫特

func version() -> String {
    let dictionary = NSBundle.mainBundle().infoDictionary!
    let version = dictionary["CFBundleShortVersionString"] as? String
    let build = dictionary["CFBundleVersion"] as? String
    return "\(version) build \(build)"
}

2
OT:您的方法存在泄漏-您alloc/ init字符串,它保留了字符串,但没有释放它。在从方法返回的对象上,通常应使用便捷方法,以便自动自动释放字符串或调用autorelease。或者: return [NSString stringWithFormat:@"%@ build %@", version, build];return [[[NSString alloc] initWithFormat:@"%@ build %@", version, build] autorelease];
nekno 2011年

1
感谢@nekno,更改了答案,因此它是ARC或非ARC友好的。
Dan Rosenstark 2011年

2
最好使用可用的常量(例如kCFBundleVersionKey),以避免输入错误。虽然,但我找不到“ CFBundleShortVersionString”的
名字

快速代码中存在错误-您两次调用CFBundleShortVersionString
Yariv Nissim 2015年

感谢@ yar1vn,我修复了它,不,它没有向后。
Dan Rosenstark

53

内部版本号是一个内部编号,指示应用程序的当前状态。它与版本号的不同之处在于,它通常不是面向用户的,并且不像版本号那样表示任何差异/功能/升级。

这样想:

  • 内部版本(CFBundleVersion):内部版本号。通常,您从1开始,并在每次构建该应用时增加1。它可以快速比较哪个构建是较新的版本,它表示代码库的进度。当进行质量检查并需要确保错误记录在正确的版本中时,这些功能可能具有极大的价值。
  • 营销版本(CFBundleShortVersionString):您用于表示此应用程序版本的面向用户的号码。通常,这遵循Major.minor版本方案(例如MyAwesomeApp 1.2),以使用户知道哪些版本是较小的维护更新,哪些是重要的新功能。

为了在您的项目中有效使用此功能,Apple提供了一个名为的出色工具agvtool我强烈建议使用此方法,因为它比编写plist更改要简单得多。 它使您可以轻松地设置内部版本号和市场版本。在编写脚本时(例如,轻松更新每个内部版本的内部版本号,甚至查询当前内部版本号是什么),它特别有用。它甚至可以做更多奇特的事情,例如在更新内部版本号时为您标记SVN。

要使用它:

  • 在“版本控制”下的Xcode中设置项目以使用“ Apple Generic”。
  • 在终端
    • agvtool new-version 1 (将内部版本号设置为1)
    • agvtool new-marketing-version 1.0 (将市场营销版本设置为1.0)

有关agvtool大量信息,请参见的手册页



25

如果内部版本号是浮点值,则上述答案中用于自动增加内部版本号的脚本对我不起作用,因此我对其进行了一些修改:

#!/bin/bash    
buildNumber=$(/usr/libexec/PlistBuddy -c "Print CFBundleVersion" "$INFOPLIST_FILE")
buildNumber=`echo $buildNumber +1|bc`
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $buildNumber" "$INFOPLIST_FILE"

21

市场版本号是针对客户的,称为版本号。它从1.0开始,并进行了2.0的主要更新, 3.0,轻微的更新到1.11.2和bug修复1.0.11.0.2。该数字与发行版和新功能有关。

版本号是大多是内部号码的建立已取得直到那时。但是有些使用其他编号,例如存储库的分支编号。该数字应该唯一,以区分几乎相同的内部版本。

如您所见,内部版本号不是必需的,它取决于您您要使用版本号。因此,如果您将其更新Xcode为主要版本,则构建字段为空。该版本字段不能为空!


要将内部版本号作为NSString变量获取:

NSString * appBuildString = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"];

为了得到 版本号作为NSString变量获取:

NSString * appVersionString = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"];

如果你想 两者合而为一NSString

NSString * versionBuildString = [NSString stringWithFormat:@"Version: %@ (%@)", appVersionString, appBuildString];

经过测试 Xcode版本4.6.3(4H1503)。内部版本号通常写在括号/大括号中。内部版本号为十六进制或十进制。

构建和版本


Xcode中,您可以自动增加内部版本号通过在项目设置的构建阶段中放置以下内容为十进制数字Run script

#!/bin/bash    
buildNumber=$(/usr/libexec/PlistBuddy -c "Print CFBundleVersion" "$INFOPLIST_FILE")
buildNumber=$(($buildNumber + 1))
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $buildNumber" "$INFOPLIST_FILE"

对于十六进制内部版本号,请使用此脚本

buildNumber=$(/usr/libexec/PlistBuddy -c "Print CFBundleVersion" "$INFOPLIST_FILE")
buildNumber=$((0x$buildNumber)) 
buildNumber=$(($buildNumber + 1)) 
buildNumber=$(printf "%X" $buildNumber)
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $buildNumber" "$INFOPLIST_FILE"

project_settings


6

感谢@nekno和@ ale84的出色答案。

但是,我修改了@ ale84的脚本,几乎没有增加浮点的内部版本号。

可以根据您的浮动格式要求更改incl的值。例如:如果incl = .01,则输出格式为... 1.19、1.20、1.21 ...

buildNumber=$(/usr/libexec/PlistBuddy -c "Print CFBundleVersion" "$INFOPLIST_FILE")
incl=.01
buildNumber=`echo $buildNumber + $incl|bc`
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $buildNumber" "$INFOPLIST_FILE"

1

另一种方法是在中设置版本号appDelegate didFinishLaunchingWithOptions

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
     NSString * ver = [self myVersion];
     NSLog(@"version: %@",ver);

     NSUserDefaults* userDefaults = [NSUserDefaults standardUserDefaults];
     [userDefaults setObject:ver forKey:@"version"];
     return YES;
}

- (NSString *) myVersion {
    NSString *version = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"];
    NSString *build = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"];
    return [NSString stringWithFormat:@"%@ build %@", version, build];
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.