# App Store Connect 构建号：版本号与构建号

> 版本号是用户看到的号码，构建号标识每次上传。两者组合必须唯一，用 Expo 时 EAS 会帮你递增构建号。

原始页面：[App Store Connect 构建号：版本号与构建号](https://devoria.fr/zh-hans/blog/app-store-connect-build-number-version)
作者：[Mehdi Azizi](https://devoria.fr/zh-hans/mehdi-azizi)
发布：2026-11-04
内容最后修订：2026-11-04


App Store Connect 里的 build number 就是构建号：`CFBundleVersion` 这个键，用来标识每一次上传。版本号 `CFBundleShortVersionString` 则是用户在 App Store 上看到的号码。**Apple 要求版本号和构建号的组合必须唯一：同一个版本下，一个构建号只能用一次。**

用 Expo 的话，版本号由你自己定，EAS 可以在每次生产构建时自动递增构建号。这篇指南会讲清楚这两个号码、Apple 的规则、ITMS-90062 和 ITMS-90189 这两个错误，以及构建没出现时该检查什么。

我用 Expo 和 EAS 发布自己的 iOS 应用，包括 Solys、TradaZen 和 Nolera。下面展示的配置就来自它们的 `eas.json` 文件。

## 版本号和构建号：有什么区别？

Info.plist 里有两个键用来标识你的应用。[Apple 关于 CFBundleShortVersionString 的文档](https://developer.apple.com/documentation/bundleresources/information-property-list/cfbundleshortversionstring)把它描述为用户可见的版本号：用点分隔的三个整数，比如 10.14.1。[关于 CFBundleVersion 的文档](https://developer.apple.com/documentation/bundleresources/information-property-list/cfbundleversion)说的是构建版本：一到三个整数，只能包含数字和点。

| 项目   | iOS 键                     | 谁能看到   | Expo 字段         |
| ------ | -------------------------- | ---------- | ----------------- |
| 版本号 | CFBundleShortVersionString | 你的用户   | `version`         |
| 构建号 | CFBundleVersion            | 你和 Apple | `ios.buildNumber` |

举个虚构的例子：版本 1.4.0 测试期间，你上传了构建 12、13 和 14，然后挑一个提交审核。[App Store Connect 帮助文档](https://developer.apple.com/help/app-store-connect/manage-builds/upload-builds)是这样概括的：版本号把构建关联到对应的版本页面，构建号则在整个系统中标识这个构建。

## Apple 的递增规则

1. **组合必须唯一。** 根据 [Xcode Cloud 的文档](https://developer.apple.com/documentation/xcode/setting-the-next-build-number-for-xcode-cloud-builds)，App Store Connect 要求版本号和构建号的组合唯一。所以 iPhone 应用在新版本里可以从 1 重新开始。Mac 应用不行：它的构建号必须一直往上涨。
2. **已批准的版本就关闭了。** Apple 一旦通过了 1.4.0，你就不能再往这个版本里加构建。下一个版本必须用更高的版本号。
3. **每一段数字按整数比较。** 1.10 排在 1.9 之后，因为 10 比 9 大。在已批准的 1.20 之后再上传 1.9，会被拒绝。

我的建议：**用一个一直递增的整数构建号，不要重置为 1。** iPhone 上允许重置，但整个应用生命周期内都唯一的构建号，能避免在 TestFlight 里把两个构建搞混。我的远程模式应用就是这样：计数器跨版本继续往上走。

## 用 Expo 和 EAS 管理版本号和构建号

[Expo 关于版本的页面](https://docs.expo.dev/build-reference/app-versions/)（2026 年 9 月 25 日更新）把分工讲得很清楚。版本号（app.json 里的 `version`）由你负责：准备新发布时自己改。构建号（`ios.buildNumber`）可以交给 EAS。Expo 还特别提到，忘记递增构建号是上传被拒的常见原因。

一切都在 eas.json 里配置：

```json
{
  "cli": {
    "appVersionSource": "remote"
  },
  "build": {
    "production": {
      "autoIncrement": true
    }
  }
}
```

- **`"remote"`**：由 EAS 服务器保存构建号。从 EAS CLI 12 起这是推荐做法。计数器从你配置里的值开始，没有的话从 1 开始，之后 `ios.buildNumber` 会被忽略。
- **`"local"`**：以你的配置为准。开启 `autoIncrement` 后，EAS 会修改你文件里的 `ios.buildNumber`，每次构建后你都得提交这个改动。
- **`autoIncrement`**：[eas.json 参考文档](https://docs.expo.dev/eas/json/)中，构建号可以填 `true` 或 `"buildNumber"`，填 `"version"` 则会递增版本号的最后一位。Expo 注明，远程模式下不支持 `"version"`。

我这边 TradaZen 和 Nolera 用的是 `remote`。Solys 还是 `local`：它的构建号保存在 app.json 里，每次生产构建都会在文件中加一。**两种都能用，但远程模式消除了忘记提交的风险。**

还有两个命令配合使用。`eas build:version:set` 用来初始化远程计数器：填入你最后一次上传给 Apple 的构建号。`eas build:version:sync` 把远程的值同步回你的项目，哪天要用 Xcode 编译时很有用。如果你用 EAS Update，远程模式不支持 `nativeVersion` 策略：Expo 建议用 `appVersion`。

## ITMS-90062：该版本已获批准

报错信息大概是这样（数字为虚构）：

```text
ERROR ITMS-90062: This bundle is invalid. The value for key
CFBundleShortVersionString [1.4.0] in the Info.plist file must
contain a higher version than that of the previously approved
version [1.4.0].
```

Apple 已经批准了 1.4.0：你不能再往里面加构建。**在 app.json 里提高版本号，比如改成 1.4.1，然后重新构建。** 只改构建号是不够的。

如果 `version` 已经更新了错误还在，找一下有没有 `ios.version` 字段。根据 [Expo 配置参考](https://docs.expo.dev/versions/latest/config/app/)，在 iOS 上它的优先级高于 `version`。类似的错误 ITMS-90186「Invalid Pre-Release Train」也是同样的解法，它表示该版本已不再接受新构建。

## ITMS-90189：Redundant Binary Upload

这次卡住的是构建号：

```text
ERROR ITMS-90189: Redundant Binary Upload. You've already uploaded
a build with build number '12' for version number '1.4.0'.
```

1.4.0 (12) 这个组合在 Apple 那边已经存在了。用 Expo 时，常见原因有四个：

- **所用的 profile 没有 `autoIncrement`。** 如果你像 Nolera 那样单独建了一个 TestFlight 用的 profile，记得把这个选项加回去。
- **远程计数器落后了。** 你在手动上传过之后才切到 `remote`：用 Apple 那边最后一个已知构建号运行 `eas build:version:set`。
- **本地模式下忘了提交。** 下一次构建又从旧号码开始。
- **你重复上传了同一个二进制。** 用 `eas submit` 时，选新的构建，别选旧的。

**解决办法永远一样：用更高的构建号重新构建。**

## 「No builds available」：构建没有出现

构建已经上传了，但版本页面里选不到。按这个顺序检查。

1. **还在处理中。** Apple 会先处理每个构建再显示出来，完成后给你发邮件。[Expo](https://docs.expo.dev/submit/ios/) 说一般需要 10 到 15 分钟。[根据 Apple](https://developer.apple.com/help/app-store-connect/manage-builds/view-builds-and-metadata)，处理超过 24 小时，就需要通过 Feedback Assistant 提交工单。
2. **在等你的加密声明。** 这就是 Missing Compliance 状态，下面会详细讲。
3. **版本号对不上。** 1.4.1 的构建不会归到 App Store Connect 里准备好的 1.5.0 版本页面下。把两者对齐。
4. **期间发布了一个版本。** 根据[选择构建的帮助文档](https://developer.apple.com/help/app-store-connect/manage-builds/choose-a-build-to-submit)，这时列表里只显示该次发布之后上传的构建。
5. **是测试员看不到。** 在 TestFlight 应用里，「no builds available」通常意味着构建不在任何群组里、在等 Beta 审核，或者已经过期。详情见 [用 TestFlight 测试你的 iPhone 应用](https://devoria.fr/zh-hans/blog/testflight-guide-test-iphone-app)。

### 需要了解的状态

下面是最常导致构建缺失的状态，来自 [Apple 的列表](https://developer.apple.com/help/app-store-connect/reference/app-build-statuses)。Processing 和 Failed 不在其中：它们是[构建跟踪](https://developer.apple.com/help/app-store-connect/manage-builds/view-builds-and-metadata)里描述的上传状态。

| 状态               | 含义               | 你的处理方法            |
| ------------------ | ------------------ | ----------------------- |
| Processing         | Apple 正在处理构建 | 等邮件                  |
| Failed             | 处理出错           | 看错误信息，重新上传    |
| Missing Compliance | 未声明加密         | 回答问题或改 Info.plist |
| Invalid Binary     | 上传不合规         | 修正后重新构建          |
| Expired            | 超过 90 天         | 重新构建                |
| Ready to Submit    | 可用于测试或审核   | 加入一个群组            |

### 一次性声明加密

没有 `ITSAppUsesNonExemptEncryption` 这个键的话，[Apple](https://developer.apple.com/documentation/bundleresources/information-property-list/itsappusesnonexemptencryption) 每个新版本都会问你合规问题。在 Expo 里，这个字段叫 `ios.config.usesNonExemptEncryption`：

```json
{
  "expo": {
    "ios": {
      "config": {
        "usesNonExemptEncryption": false
      }
    }
  }
}
```

`false` 的意思是：没有加密，或者只用了豁免的加密。[Apple 指出](https://developer.apple.com/documentation/security/complying-with-encryption-export-regulations)，系统内置的加密，比如 HTTPS 连接，一般属于豁免范围，而且这个回答也涵盖你用到的库。我的三个应用都声明为 `false`。**只有在你的应用确实如此时才填 `false`：这个声明是要你负责的。**

## 已上传构建的构建号能改吗？

不能。构建号写在已签名的二进制文件里：要改，只能重新构建。

你能改的是关联到版本的那个构建。Apple 规定每个版本只能有一个构建，但在提交审核之前，[你可以随意替换](https://developer.apple.com/help/app-store-connect/manage-builds/choose-a-build-to-submit)：

1. 在 App Store Connect 里打开该版本，找到 Build 部分。
2. 鼠标悬停在当前构建上，点击删除按钮，也就是减号。
3. 点击添加按钮，也就是加号，选择正确的构建，然后保存。

从版本中移除构建，并不会把它从你的账号里删掉。如果版本已经在审核中，[先撤回提交](https://developer.apple.com/help/app-store-connect/manage-submissions-to-app-review/remove-a-submission-from-review)：审核会从头开始。

## 下次上传之前

构建号只是上传时的检查项之一。构建镜像可能触发 [ITMS-90725](https://devoria.fr/zh-hans/blog/itms-90725-sdk-version-issue-expo)，签名也有自己的坑，详见 [iOS 开发者证书和 provisioning profile](https://devoria.fr/zh-hans/blog/ios-certificate-provisioning-profile-expo)。从构建到 TestFlight 的完整流程见 [没有 Mac 也能发布 iOS 应用](https://devoria.fr/zh-hans/blog/publish-ios-app-without-mac-expo-eas)，审核时长见 [App Store 审核需要多久](https://devoria.fr/zh-hans/blog/app-store-review-time-how-long)。所有步骤都汇总在 [在 App Store 上发布应用](https://devoria.fr/zh-hans/expertise/publish-an-app-on-the-app-store) 页面。

如果你在准备第一次发布，[做一下免费诊断](https://devoria.fr/zh-hans/diagnostic)：它会告诉你项目里卡在哪里，并把我的 Apple 防拒审清单发给你。要构建应用、接入订阅并发布，[iOS & Android Kit](https://devoria.fr/zh-hans/kits/ios) 会带你按四个步骤走完全程，附带我自己应用的起步代码，按你自己的节奏来。

## 常见问题

### App Store Connect 上的版本号和构建号有什么区别？

版本号是你这次发布的公开号码，比如 1.4.0。构建号标识为这个版本上传给 Apple 的某一个具体二进制文件。同一个版本可以上传多个构建，每个都有自己的号码。

### 每次上传都要改构建号吗？

同一个版本下，要。Apple 会拒绝版本号和构建号组合相同的第二次上传，这就是 ITMS-90189 错误。用 EAS 的话，`autoIncrement` 会在每次生产构建时自动处理。

### 每个新版本的构建号都要从 1 重新开始吗？

不是必须的。在 iPhone 上，Apple 接受新版本使用更低的构建号，因为只要求组合唯一。不过一直递增的计数器更容易跟踪。

### 怎么在 App Store Connect 里修改构建号？

已经上传的构建，构建号改不了。但只要版本还没进入审核，你可以在版本页面的 Build 部分替换关联的构建。想要新号码，就重新构建。

### 为什么我的构建没有出现在 App Store Connect 里？

最常见的原因是还在处理中，或者在等你的加密声明。也检查一下它的版本号和版本页面是否一致。处理超过 24 小时，Apple 要求提交工单。


## 你的项目

[Review Kit](https://devoria.fr/zh-hans/kits/app-review)：我的 App Store 审核清单、我被 Apple 拒审后的修正方案、Google Play 审核清单，以及三个 Claude Code skill。¥369。

[iOS & Android Kit](https://devoria.fr/zh-hans/kits/ios)：用 Claude Code 打造你的 iPhone 和 Android 应用：我自己应用的起步代码、上架商店的完整流程，以及全部工具包。¥739。

[诊断：你离自己的 iPhone 应用还差什么](https://devoria.fr/zh-hans/diagnostic)：7 个问题，60 秒：看清真正阻碍你发布 iPhone 应用的原因，拿到你的 4 步路线和适合你的套件。
