# Build number в App Store Connect: версия и номер сборки

> Версию видят твои клиенты, а build number идентифицирует каждую загрузку. Пара должна быть уникальной: в Expo номер сборки за тебя поднимает EAS.

Оригинальная страница: [Build number в App Store Connect: версия и номер сборки](https://devoria.fr/ru/blog/app-store-connect-build-number-version)
Автор: [Mehdi Azizi](https://devoria.fr/ru/mehdi-azizi)
Опубликовано: 2026-11-04
Последняя правка контента: 2026-11-04


Build number в App Store Connect означает номер сборки: ключ `CFBundleVersion`, который идентифицирует каждую загрузку. Версия, `CFBundleShortVersionString`, это номер, который твои клиенты видят в App Store. **Apple требует, чтобы пара «версия + номер сборки» была уникальной: один номер сборки используется для одной версии только один раз.**

В Expo версию ты задаёшь сам, а EAS может увеличивать номер сборки при каждом production-билде. В этом гайде разберём оба номера, правила Apple, ошибки ITMS-90062 и ITMS-90189 и что проверить, если твоя сборка не появляется.

Я публикую свои iOS-приложения через Expo и EAS, среди них 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.9, отправленную после одобренной 1.20, отклонят.

Мой совет: **держи целочисленный номер сборки, который всегда растёт, и не сбрасывай его на 1.** Сброс на 1 на iPhone разрешён, но номер, уникальный на всю жизнь приложения, избавляет от путаницы между двумя сборками в TestFlight. Так у меня и выходит в приложениях в удалённом режиме: счётчик продолжается от версии к версии.

## Управление версией и сборкой в Expo и EAS

[Страница Expo о версиях](https://docs.expo.dev/build-reference/app-versions/), обновлённая 25 сентября 2026 года, разделяет роли. Версия (`version` в app.json) остаётся за тобой: ты меняешь её, когда готовишь новый релиз. Номер сборки (`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, и каждый production-билд поднимает его в файле. **Оба варианта работают, но удалённый режим убирает риск забытого коммита.**

Систему дополняют две команды. `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 чаще всего встречаются четыре причины:

- **В используемом профиле нет `autoIncrement`.** Если ты создаёшь отдельный профиль для TestFlight, как у Nolera, добавь туда эту опцию.
- **Удалённый счётчик отстаёт.** Ты перешёл на `remote` после ручных загрузок: запусти `eas build:version:set` с последним номером, известным Apple.
- **В локальном режиме забыли коммит.** Следующий билд стартует со старого номера.
- **Ты повторно отправляешь тот же бинарник.** В `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 не попадёт в карточку, подготовленную под 1.5.0 в App Store Connect. Выровняй их.
4. **За это время вышла версия.** Согласно [справке о выборе сборки](https://developer.apple.com/help/app-store-connect/manage-builds/choose-a-build-to-submit), тогда список показывает только сборки, загруженные после этого релиза.
5. **Сборку не видит тестировщик.** В приложении TestFlight «no builds available» часто означает, что сборка не входит ни в одну группу, ждёт бета-ревью или истекла. Подробности в статье [TestFlight для тестирования приложения для iPhone](https://devoria.fr/ru/blog/testflight-testirovanie-iphone-prilozheniya).

### Статусы, которые нужно знать

Статусы, которые чаще всего объясняют отсутствие сборки, по [списку 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/ru/blog/itms-90725-sdk-version-issue-expo), а у подписи свои ловушки, о них в статье [сертификат разработчика iOS и provisioning profile](https://devoria.fr/ru/blog/ios-developer-certificate-provisioning-profile-expo). Вся цепочка от билда до TestFlight описана в статье [опубликовать iOS-приложение без Mac](https://devoria.fr/ru/blog/publish-ios-app-without-mac-expo-eas), а сроки ревью в статье [сроки проверки в App Store](https://devoria.fr/ru/blog/sroki-proverki-app-store-skolko-zhdat). Все шаги собраны на странице [опубликовать приложение в App Store](https://devoria.fr/ru/expertise/publish-app-on-app-store).

Если готовишь первый релиз, [пройди бесплатную диагностику](https://devoria.fr/ru/diagnostic): она покажет, что блокирует твой проект, и пришлёт мой чек-лист против отказов Apple. Чтобы создать приложение, подключить подписки и опубликовать его, [iOS & Android Kit](https://devoria.fr/ru/kits/ios) ведёт по пути из четырёх шагов со стартовым кодом моих приложений, в твоём темпе.

## Частые вопросы

### В чём разница между версией и build number в App Store Connect?

Версия это публичный номер твоего релиза, например 1.4.0. Build number идентифицирует конкретный бинарник, отправленный в Apple для этой версии. Для одной версии можно отправить несколько сборок, у каждой свой номер.

### Нужно ли менять номер сборки при каждой загрузке?

Да, в рамках одной версии. Apple отклоняет повторную загрузку с той же парой «версия + номер сборки», это ошибка ITMS-90189. В EAS об этом заботится `autoIncrement` при каждом production-билде.

### Должен ли номер сборки начинаться с 1 для каждой версии?

Это не обязательно. На iPhone Apple принимает более низкий номер для новой версии, потому что уникальной должна быть только пара. Счётчик, который всегда растёт, проще отслеживать.

### Как изменить build number в App Store Connect?

Номер уже отправленной сборки изменить нельзя. Зато можно заменить сборку, привязанную к версии, в разделе Build карточки, пока она не на ревью. Для нового номера сделай новый билд.

### Почему моя сборка не появляется в App Store Connect?

Чаще всего она ещё обрабатывается или ждёт декларации о шифровании. Проверь также, что её версия совпадает с версией в карточке. Если обработка длится больше 24 часов, Apple просит открыть тикет.


## Твой проект

[Review Kit](https://devoria.fr/ru/kits/app-review): Мой чек-лист для ревью в App Store, исправленные отказы Apple, чек-лист для Google Play и три скилла для Claude Code. 55 $.

[iOS & Android Kit](https://devoria.fr/ru/kits/ios): Создай своё приложение для iPhone и Android с Claude Code: стартовый код моих приложений, путь до публикации в сторах и все киты. 109 $.

[Диагностика: что отделяет тебя от твоего iPhone-приложения](https://devoria.fr/ru/diagnostic): 7 вопросов, 60 секунд: ты узнаешь, что на самом деле мешает тебе опубликовать iPhone-приложение, получишь путь из 4 этапов и подходящий тебе кит.
