协慌网

登录 贡献 社区

Xcode 中的版本与构建

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

我的问题是:

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

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

答案

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

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

查看 “信息” 选项卡时,如果右键单击并选择 “显示原始键 / 值” ,则会看到实际名称为CFBundleShortVersionString (Version)和CFBundleVersion (Build)。

通常使用该版本,就像您在 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 中删除了 “更多信息...”按钮,因此也可以从“系统信息”应用程序的 “软件”>“开发人员”部分获得此信息,方法是打开 “苹果”菜单 >“关于本机” >“系统报告...”

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

iPhone Simulator 的版本 / 内部版本号与 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文件,则有其他可选步骤。

这是从此处的 how-to 文章扩展而来的。

在 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 PreferenceSpecifiers数组下的索引 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

(请留在这里供我自己参考。)这将显示您在 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)"
}

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

这样想:

  • 内部版本( 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 (将 Marketing 版本设置为 1.0)

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