Xcode中的版本与构建

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

我的问题是:

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

  2. 为什么升级到Xcode 4后版本字段为空?

177561 次浏览

苹果对这些领域进行了重新排列/重新利用。

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

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

版本通常是您在Xcode 3中使用它的方式。我不确定您在什么级别上询问版本/构建差异,所以我会从哲学上回答它。

有各种各样的计划,但最受欢迎的是:

{主要版本}.{小版本}.{修订版}

  • 主要版本-主要更改、重新设计和功能 更改
  • 次要版本-小改进,增加功能
  • 修订时间-用于bug修复的补丁号

然后单独使用构建来指示一个版本或整个产品生命周期的构建总数。

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

  • 版本1.0.0可能是构建542。需要542个构建才能到达 1.0.0版本。
  • 版本1.0.1可能是构建578。
  • 版本1.1.0可能是Build 694。
  • 版本2.0.0可能是build 949。

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

如果您转到Xcode菜单>关于Xcode,您将看到版本和内部版本号。如果您点击更多信息…按钮,您将看到一堆不同的版本。由于更多信息…按钮在Xcode 5中被删除,因此此信息也可从系统信息应用程序的软件>开发者部分获得,可通过打开苹果菜单>关于此Mac>系统报告…获得。

例如,Xcode 4.2(4C139)。营销版本4.2是Build主要版本4、Build次要版本C和Build编号139。下一个版本(大概是4.3)可能是Build版本4D,Build编号将从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中,在右下角,单击添加构建阶段按钮并选择添加运行脚本
    • 在Xcode 5中,选择编辑器菜单>添加构建阶段>添加运行脚本构建阶段
  5. 拖放新的运行脚本阶段以将其移动到复制捆绑包资源阶段之前(此时app-info.plist文件将与您的应用程序捆绑)。
  6. 在新的运行脚本阶段,设置壳牌/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值以匹配您的设置。#EYZ1表示查看plist文件中PreferenceSpecifiers数组下索引2处的项目,因此对于基于0的索引,这是数组中的第三个首选项设置。

    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. And if you have a universal app for iPad & iPhone, then you can also set the settings for the iPhone file:

    /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
    

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

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

在Swift

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

如果构建号是浮点值,上面答案中自动递增构建号的脚本对我不起作用,所以我稍微修改了一下:

#!/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"

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

这样想:

  • 构建(CFBundleVersion):构建的数量。通常你从1开始,并随着应用程序的每次构建而增加1。它可以快速允许比较哪个构建是最近的,并且它表示代码库的进度感。当使用QA并且需要确保根据正确的构建记录错误时,这些可能非常有价值。
  • 营销版本(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的手册页,了解大量信息

市场发布号是针对客户的,称为版本号。它以1.0开头,对于2.03.0的主要更新,对于1.11.2的次要更新以及对1.0.11.0.2的bug修复,它会上升。这个数字是面向版本和新功能的。

版本号主要是在此之前制作的内部构建数。但是有些使用其他数字,例如存储库的分支编号。这个数字应该是独特来区分不同的几乎相同的构建。

如您所见,版本号不是必需的,您可以自行决定要使用哪个版本号。因此,如果您将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

感谢@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"

另一种方法是在appDelegatedidFinishLaunchingWithOptions中设置版本号:

- (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];
}