Чтобы выпустить приложение, нужны аккаунты Apple Developer Program и Google Play Console, уникальные идентификаторы приложения, подписанные релизные сборки (.ipa и .aab) и заполненные карточки с политикой конфиденциальности и ответами о данных. Для Expo сборку и отправку автоматизируют EAS Build и EAS Submit, во Flutter — flutter build appbundle и flutter build ipa. Чаще всего ревью не проходят незавершённые приложения: падения, заглушки, нерабочие ссылки и отсутствие тестового аккаунта.
После материала вы сможете
- выбрать тип аккаунта разработчика в Apple и Google и подготовить документы для организации, включая D-U-N-S
- настроить
app.jsonиeas.jsonдля релизной сборки с автоувеличением build number и отправить сборку командойeas submit - подготовить карточку: иконку, скриншоты, политику конфиденциальности, App Privacy и Data safety, доступ для ревьюера
- проверить релиз по чек-листу частых причин отказа и понять, что можно обновлять через OTA, а что требует новой сборки
Что знать заранее
Проверено на
Expo SDK 57EAS CLI 24.12 (@expo/eas-json 24.9)Node.js 24 LTS (24.18)
Сверено с документацией: 11 октября 2026 г.
Содержание
Аккаунты разработчика: на кого оформлять
Приложение в сторе всегда принадлежит аккаунту разработчика, и имя владельца аккаунта видят пользователи как продавца. Поэтому первый вопрос релиза — не технический: на кого регистрировать аккаунт. У обеих платформ есть личные аккаунты и аккаунты организаций, и требования к ним разные.
Типы аккаунтов
- Apple Developer Program
- Individual (в том числе индивидуальный предприниматель) и Organization
- Google Play Console
- Personal и Organization
Что нужно организации
- Apple Developer Program
- Юрлицо, способное заключать договоры; номер D-U-N-S; рабочий сайт на домене организации; право подписи у регистрирующего
- Google Play Console
- Номер D-U-N-S, сайт и телефон организации, контактное лицо
Что видят пользователи
- Apple Developer Program
- Для личного аккаунта — ваше юридическое имя, для организации — название юрлица
- Google Play Console
- Для личного — юридическое имя, страна и email разработчика (полный адрес — если приложение монетизируется); для организации — название, юридический адрес, email и телефон
Стоимость на официальной странице
- Apple Developer Program
- 99 USD за год членства; цена может отличаться по регионам и показывается в местной валюте при регистрации
- Google Play Console
- Единоразовый регистрационный сбор 25 USD
Особые условия
- Apple Developer Program
- Apple Account с двухфакторной аутентификацией; освобождение от оплаты возможно для некоммерческих, образовательных и государственных организаций
- Google Play Console
- Возраст от 18 лет; проверка личности; новые личные аккаунты подтверждают доступ к Android-устройству и проходят закрытый тест
D-U-N-S — девятизначный идентификатор организации в базе Dun & Bradstreet. По справке Google Play его можно получить бесплатно, но процесс занимает до 30 дней, а платные посредники для этого не нужны. Закладывайте этот срок в план, если у компании номера ещё нет.
Идентификаторы, версии и подпись
У приложения три вида «имени», и путать их нельзя. Идентификатор — bundleIdentifier на iOS и package (applicationId) на Android — уникален в сторе и после публикации не меняется: новый идентификатор означает новое приложение. Версия для пользователей (1.2.0) видна в карточке. Номер сборки (build number на iOS, versionCode на Android) нужен только сторам и должен расти с каждой загрузкой.
Версия для пользователя
- Expo (
app.json) version- Flutter (
pubspec.yaml) - часть до
+вversion: 1.0.0+1 - iOS
CFBundleShortVersionString- Android
versionName
Номер сборки
- Expo (
app.json) ios.buildNumber,android.versionCode(или удалённо в EAS)- Flutter (
pubspec.yaml) - часть после
+ - iOS
CFBundleVersion- Android
versionCode— целое число до 2100000000
По документации Expo, одна из частых причин отказа при загрузке — повторный номер сборки: разработчик забыл его увеличить. Поэтому Expo рекомендует хранить номера сборок на серверах EAS (appVersionSource: "remote") и увеличивать их автоматически, а версию для пользователя менять вручную при каждом релизе.
Подпись подтверждает, что обновление выпустил тот же разработчик. На Android используется схема из двух ключей: вы подписываете .aab upload-ключом, а Google по Play App Signing переподписывает APK ключом подписи приложения, который хранит у себя. Для новых приложений Play App Signing обязательна. Если upload-ключ потерян или скомпрометирован, его можно сбросить через Play Console. На iOS нужны сертификат распространения (distribution certificate, общий для всех приложений аккаунта) и профиль подготовки (provisioning profile) для каждого приложения; профили действуют 12 месяцев, но их истечение не влияет на уже опубликованное приложение.
Сборка и отправка: EAS Build и EAS Submit
EAS Build собирает подписанные .aab и .ipa в облаке Expo, EAS Submit загружает их в Google Play Console и App Store Connect. Оба работают с macOS, Linux и Windows, так что для выпуска iOS-версии из Expo-проекта Mac не обязателен. Начните с идентификаторов в конфигурации приложения.
{
"expo": {
"name": "Callback",
"slug": "callback",
"version": "1.0.0",
"orientation": "portrait",
"icon": "./assets/icon.png",
"userInterfaceStyle": "light",
"ios": {
"bundleIdentifier": "kz.example.callback",
"supportsTablet": false
},
"android": {
"package": "kz.example.callback",
"adaptiveIcon": {
"backgroundColor": "#E6F4FE",
"foregroundImage": "./assets/android-icon-foreground.png",
"backgroundImage": "./assets/android-icon-background.png",
"monochromeImage": "./assets/android-icon-monochrome.png"
}
}
}
}ios.buildNumber и android.versionCode не указаны: номера сборок хранит EAS{
"cli": {
"version": ">= 18.0.0",
"appVersionSource": "remote"
},
"build": {
"preview": {
"distribution": "internal",
"android": {
"buildType": "apk"
}
},
"production": {
"autoIncrement": true
}
},
"submit": {
"production": {
"android": {
"track": "internal",
"releaseStatus": "draft"
},
"ios": {
"ascAppId": "1234567890"
}
}
}
}ascAppId — числовой Apple ID приложения из App Store Connect (здесь пример), строка из букв не пройдёт проверку схемыcli.appVersionSource: "remote"иautoIncrement: true— EAS сам увеличиваетversionCodeи build number при каждой продакшн-сборке.- Профиль
previewсобирает APK для установки на устройства команды; в Google Play APK не загрузить — для стора нужен.aab, его и собирает профильproductionпо умолчанию. track: "internal"отправляет сборку во внутреннее тестирование,releaseStatus: "draft"создаёт черновик релиза без выкатки — завершаете его в Play Console.- Для отправки в Google Play EAS нужен JSON-ключ сервисного аккаунта Google: его загружают в EAS через панель или
eas credentials.
npm install --global eas-cli
eas login
# сборка для сторов: .aab для Google Play и .ipa для App Store
eas build --platform all --profile production
# отправка последней сборки по профилю submit.production
eas submit --platform android --latest
eas submit --platform ios --latest
# или сборка и отправка одной командой
eas build --platform all --profile production --auto-submit$ npx expo config --type public --json
{
"name": "Callback",
"slug": "callback",
"version": "1.0.0",
"sdkVersion": "57.0.0",
"platforms": ["ios", "android"],
"ios": {
"bundleIdentifier": "kz.example.callback",
"supportsTablet": false
},
"android": {
"package": "kz.example.callback",
...
}
}После eas submit iOS-сборка появляется в TestFlight после обработки, а в App Review её отправляют вручную в App Store Connect. В Google Play первая отправка создаёт релиз во внутреннем тестировании, но приложение остаётся черновиком, пока не заполнены карточка и разделы App content.
Во Flutter версия задаётся одной строкой в pubspec.yaml, а сборки — командами Flutter CLI. Android-сборку подписывают upload-ключом через android/key.properties, iOS собирают только на Mac с Xcode.
version: 1.0.0+1--build-name и --build-number# Android: App Bundle, подписанный upload-ключом из android/key.properties
flutter build appbundle
# результат: build/app/outputs/bundle/release/app.aab
# iOS (только macOS с Xcode): архив и .ipa для App Store Connect
flutter build ipa
# результат: build/ios/ipa/*.ipa — загрузка через Transporter или XcodeАльтернативы EAS: локальная сборка (eas build --local), Android Studio и Xcode вручную, а для CI — инструменты вроде Codemagic и fastlane, которые упоминает документация Flutter. Механика везде одна: подписанный артефакт с новым номером сборки загружается в консоль стора.
Карточка приложения: иконки, скриншоты, приватность
Карточка — то, что видит пользователь до установки, и то, что первым проверяет ревьюер. Требования App Review прямо говорят: метаданные, включая описание, скриншоты и информацию о приватности, должны точно отражать основной опыт приложения, а скриншоты — показывать приложение в работе, а не только заставку или экран входа.
Иконка
- App Store
- Задаётся в сборке (в Expo —
iconвapp.json) - Google Play
- 512 × 512 px, 32-битный PNG с альфа-каналом, до 1024 КБ
Скриншоты
- App Store
- От 1 до 10 на размер дисплея, JPEG или PNG без прозрачности; при одинаковом интерфейсе достаточно старшего разрешения — App Store Connect уменьшит его сам
- Google Play
- Минимум 2, до 8 на тип устройства, JPEG или 24-битный PNG; стороны 320–3840 px, длинная не больше двух коротких
Дополнительно
- App Store
- Превью-видео по желанию
- Google Play
- Графический баннер 1024 × 500 px; для попадания в рекомендации — от 4 скриншотов с разрешением от 1080 px
Политика конфиденциальности
- App Store
- Ссылка обязательна для всех приложений: в App Store Connect и внутри приложения
- Google Play
- Ссылка нужна для раздела Data safety, в том числе если приложение не собирает данных
Ответы о данных
- App Store
- App Privacy: какие данные собираете вы и подключённые SDK
- Google Play
- Data safety: сбор, передача третьим лицам, шифрование, удаление
Политика конфиденциальности — это публичная страница на сайте, а не PDF в почте. Она описывает, какие данные собирает приложение, зачем, кому передаёт и как пользователь может их удалить. Ответы в App Privacy и Data safety должны совпадать с реальным поведением приложения и всех подключённых библиотек: аналитики, рекламы, SDK для push-уведомлений. За расхождения Google применяет санкции, а Apple требует держать ответы актуальными.
- Если в приложении можно создать аккаунт, в нём должно быть и удаление аккаунта: это требуют и Apple (5.1.1(v)), и Google Play — последний дополнительно просит веб-ссылку на запрос удаления
- Если часть функций закрыта входом, ревьюеру нужен рабочий тестовый аккаунт и инструкция: в App Review Information в App Store Connect и в разделе App access в Play Console
- Тексты запросов разрешений (камера, геолокация) объясняют, зачем доступ нужен пользователю
- Возрастной рейтинг: анкета контента в Play Console (без неё приложение останется без рейтинга и может быть удалено) и возрастной рейтинг в App Store Connect
- Если используется вход через сторонние сервисы, проверьте требования раздела 4.8 App Review Guidelines к альтернативному способу входа
Ревью: частые причины отказа
Apple сообщает, что в среднем более 40% нерешённых проблем на ревью связаны с правилом 2.1 App Completeness — завершённостью приложения. По данным той же страницы, App Review рассматривает не менее 50% заявок быстрее чем за 24 часа и 90% — быстрее чем за 48 часов; неполная заявка рассматривается дольше. Google Play сроков ревью в справке о подготовке к проверке не называет.
App Store: что проверить
- Падения и ошибки: тестируйте на устройствах с последней версией ОС
- Нерабочие ссылки; обязательны ссылки на поддержку и на политику конфиденциальности
- Заглушки: временные тексты и картинки, пустые разделы
- Нет тестового аккаунта или инструкций для функций за логином
- Скриншоты не соответствуют приложению
- Приложение — по сути обёртка сайта без «приложенческой» ценности (4.2 Minimum Functionality)
- Непонятные запросы доступа к данным
Google Play: что проверить
- Нет политики конфиденциальности или она недоступна по ссылке
- Ответы в Data safety расходятся с реальным поведением приложения и SDK
- Нет инструкций и учётных данных в App access
- Целевой API ниже требуемого: с 31 августа 2026 новые приложения и обновления должны таргетировать Android 16 (API 36)
- Чувствительные разрешения без декларации (SMS, журнал звонков)
- Нет удаления аккаунта внутри приложения и по веб-ссылке
- Метаданные вводят в заблуждение, приложение не даёт базовой функциональности
Если App Review отклонил сборку, в App Store Connect указано, какие правила нарушены, и можно переписываться с ревьюером, чтобы решить вопрос до повторной отправки. Если вы считаете, что приложение поняли неверно, есть апелляция в App Review Board — одна на каждую отклонённую заявку, с конкретными доводами. Для Google Play порядок тот же: исправьте приложение или декларации в Play Console и отправьте исправленную версию на повторную проверку.
Обновления и OTA: что можно без ревью
Каждый новый бинарник проходит тот же путь: новый номер сборки, загрузка, ревью. Expo-проекты могут доставлять часть изменений по воздуху (OTA, over-the-air) через EAS Update: приложение с библиотекой expo-updates скачивает новый JavaScript-бандл и ресурсы при следующем запуске.
npx expo install expo-updates
eas update:configure
# после новой сборки с expo-updates:
eas update --channel production --message "Fix login button alignment"Исправление бага или падения в JavaScript-коде
- Через EAS Update
- Да
- Нужна новая сборка
- Нет
Тексты, переводы, стили, раскладка экранов
- Через EAS Update
- Да
- Нужна новая сборка
- Нет
Нативный код или нативные зависимости
- Через EAS Update
- Нет
- Нужна новая сборка
- Да
Новые разрешения (камера, геолокация)
- Через EAS Update
- Нет
- Нужна новая сборка
- Да
Обновление версии Expo SDK
- Через EAS Update
- Нет
- Нужна новая сборка
- Да
Чек-лист релиза для обоих сторов
- Аккаунты Apple и Google оформлены на владельца продукта, у команды есть доступ через роли
bundleIdentifierиpackageокончательные и совпадают с записями в App Store Connect и Play Console- Версия для пользователя увеличена, номер сборки растёт автоматически (
autoIncrement) или вручную - Ключи подписи и сервисные ключи хранятся вне репозитория, есть резервная копия и понятно, у кого доступ
- Сборка прошла тестовый канал: TestFlight и внутреннее тестирование Google Play, для нового личного аккаунта — закрытый тест 14 дней
- Иконка, скриншоты и описание соответствуют текущей версии приложения
- Политика конфиденциальности опубликована, ссылка есть в карточке и внутри приложения
- App Privacy и Data safety заполнены с учётом всех SDK
- Удаление аккаунта доступно в приложении (и по веб-ссылке для Google Play)
- Тестовый аккаунт и инструкции для ревьюера указаны, бэкенд включён на время ревью
- Целевой API Android соответствует текущему требованию Google Play
Дальше — эксплуатация: следите за отчётами о падениях в консолях сторов, отвечайте на отзывы и планируйте обновления под регулярное повышение требований Google Play к целевому API Android. Если приложение использует push-уведомления, проверьте ключи APNs и настройки Firebase до релиза — об этом отдельный материал.
Как проверено1 · пройдено1 · частично3 · не запускалосьсверено 11 октября 2026 г.
- запущено, работает
app.json (ios.bundleIdentifier, android.package, version)
временный проект create-expo-app blank-typescript (Expo SDK 57.0.27); npx expo config --type public --json — конфиг разрешается без ошибок; npx expo config --type introspect — version 1.0.0 → CFBundleShortVersionString, package kz.example.callback в манифесте
- частично
eas.json (cli.appVersionSource remote, build preview/production, submit production android/ios)
схема проверена библиотекой @expo/eas-json 24.9.0 (EasJsonUtils.getBuildProfileAsync/getSubmitProfileAsync/getCliConfigAsync для android и ios) — профили разрешаются; первая версия с ascAppId-плейсхолдером из букв была отклонена валидатором (нужны только цифры) — исправлено на пример из документации; `eas config`/`eas build` (eas-cli 24.12.1) требуют входа в аккаунт Expo — не запускались
- не запускалось
Команды eas build / eas submit / --auto-submit
флаги сверены с `eas build --help` и `eas submit --help` (eas-cli 24.12.1: -p android|ios|all, --profile, --latest, --auto-submit); реальная сборка и публикация не выполнялись — нет аккаунтов и ключей
- не запускалось
EAS Update команды (expo-updates, eas update)
из документации EAS Update; не запускались
- не запускалось
Flutter: version в pubspec.yaml, flutter build appbundle / flutter build ipa
по docs.flutter.dev/deployment/android и /ios; релизная подпись и iOS-сборка (macOS + Xcode) на машине недоступны
«Запущено» — код выполнен во временном проекте или контейнере, вывод в статье взят из прогона. «Частично» — проверено с заглушками вместо внешних сервисов. «Не запускалось» — нужны устройство, аккаунт или ключ; шаги сверены с официальной документацией. Файлы проверочного проекта и логи запусков сохранены в архиве InterLAB.