versionCode хранит целое число, по которому Play упорядочивает сборки и решает, что считать обновлением: оно должно расти с каждой загрузкой и никогда не используется повторно. versionName содержит произвольную строку, которую видит пользователь, и Play её не проверяет.
**versionCode**: уникален для пакета во всех треках, максимум 2100000000; номер считается занятым, даже если релиз удалили или так и не выпустили
Версия только растёт: Android не установит меньший versionCode поверх большего, поэтому повторная загрузка старого бандла ничего не откатит
**versionName**: например "8.4.0"; может повторяться и нужен пользователям и поддержке
В iOS та же пара: CFBundleVersion (номер сборки) и CFBundleShortVersionString (маркетинговая версия)
AndroidMiddle
Релиз и ревью в сторах
App Store Connect, Play Console, реджекты ревью, phased release, форс-апдейт, политики
Закрыто вопросов
0 / 16
- 0Повторить
Вопросы
В Play есть треки internal, closed и open testing плюс production: internal testing доходит до 100 тестировщиков за минуты, а релизы в closed и open проходят ревью как продакшен. TestFlight делится так же, на внутренних и внешних тестировщиков.
Internal testing: до 100 тестировщиков из списка email, сборка доступна через несколько минут после загрузки; для QA и команды
Closed и open testing: closed для приглашённых списков email или Google Groups (closed-треков может быть несколько); open позволяет любому присоединиться со страницы приложения как публичная бета; оба проходят ревью до выдачи тестировщикам
Internal app sharing: вне треков: загружаете любой AAB или APK, получаете ссылку, правила versionCode не действуют; удобно для проверки ветки
TestFlight: внутренние тестировщики (до 100 пользователей App Store Connect) получают сборку сразу после обработки; внешние (до 10 000) ждут Beta App Review для первой сборки версии; любая сборка истекает через 90 дней
Личные аккаунты разработчика, созданные после 13 ноября 2023 года, сначала должны провести закрытое тестирование минимум с 12 тестировщиками, которые остаются подписанными 14 дней подряд, а затем подать заявку на доступ к продакшену в Play Console.
Тестировщики должны остаться: они подписываются на closed-трек и не отписываются все 14 дней (до декабря 2024 года порог был 20); трек internal testing не засчитывается
Заявка: анкета о том, как вы набирали тестировщиков, какой фидбек получили и что изменили; пустые ответы отклоняют, и тестировать приходится заново
Аккаунты организаций освобождены: аккаунт компании, подтверждённый номером D-U-N-S, сразу публикует в продакшен; это одна из причин публиковаться от организации
Загрузка лишь передаёт бинарник в стор: дальше его обрабатывают, проверяют на ревью и выпускают, и на каждом шаге сборка может застрять или получить отказ. «Одобрено» ещё не значит «доступно».
Обработка: Play проверяет AAB и генерирует APK за минуты; Apple переподписывает сборку и оптимизирует её под устройства (app thinning), обычно 5–30 минут, а ошибки валидации присылает письмом с кодами ITMS-…
Pre-launch report: для тестовых треков Play запускает сборку на реальных устройствах в Firebase Test Lab, и краши видны ещё до ревьюера
Ревью: Apple обычно отвечает в течение 24 часов; в Play обновление часто проходит за часы, но может занять до недели, а новое приложение или чувствительное разрешение проверяют дольше
Релиз: Apple выпускает автоматически, вручную или в заданную дату; Play публикует сразу после одобрения, если его не держит managed publishing
Раскатка: поэтапный релиз всё равно идёт днями, и каждое устройство обновляется по своему расписанию
APK представляет собой устанавливаемый пакет, а AAB служит форматом публикации, который установить нельзя. Play превращает его в базовый APK и split-APK по ABI, плотности экрана и языку, подписывает их ключом подписи приложения и отдаёт каждому устройству только нужное.
Обязателен для новых приложений: с августа 2021 года; загрузка APK осталась для старых приложений и других сторов
Меньше размер загрузки: телефон получает один ABI и одну плотность вместо всех; по данным Google в среднем на 15% меньше, а для приложений с несколькими нативными ABI выигрыш заметно больше
Play App Signing обязателен: вы подписываете AAB ключом загрузки (upload key), а Play переподписывает своим ключом подписи приложения, поэтому SHA-256 для Firebase, Maps и App Links берётся из Play Console
Play Feature Delivery: динамические feature-модули, которые ставятся при установке, по условию или по запросу через SplitInstallManager
Play Asset Delivery: крупные ресурсы вроде игровых данных или ML-моделей уходят в asset packs, вне лимита около 200 МБ сжатой базовой загрузки
Другие сторы и QA: собирайте APK локально через bundletool; --mode=universal даёт один APK со всем содержимым
В Play страница приложения публикуется отдельно от релизов, поэтому новый текст и скриншоты выходят после короткого ревью листинга. В App Store почти все метаданные привязаны к версии приложения, так что придётся отправить новую версию, даже если код не менялся.
Play: описание, иконка, feature graphic и скриншоты проходят ревью и публикуются без AAB; managed publishing позволяет придержать их до нужного момента
App Store, можно менять в любой момент: promotional text (170 символов), цена и доступность, ответы о приватности
App Store, нужна версия: название, подзаголовок, описание, ключевые слова, скриншоты и What's New; эта версия проходит ревью и может быть отклонена
Без бинарника, но с ревью: custom product pages и in-app events у Apple, custom store listings и store listing experiments в Play
Храните это в репозитории: fastlane deliver и supply держат метаданные в файлах, и изменение листинга превращается в diff, который можно проверить
Каждый год Play требует, чтобы новые приложения и обновления таргетили свежий API level: с 31 августа 2026 года это API 36 (Android 16). Если пропустите срок, Play не примет загрузку, а приложение, отставшее ещё сильнее, перестанет предлагаться новым пользователям на новых устройствах.
Зачем это нужно: targetSdk включает для приложения новые правила платформы; дедлайн не даёт жить по старым вечно
Переключатель поведения, а не число: таргет 36 убирает возможность отказаться от edge-to-edge, которая оставалась при 35, по умолчанию включает системные анимации predictive back и игнорирует блокировку ориентации и ресайза на экранах от 600dp
**minSdk остаётся вашим решением: стор его не навязывает; пользователи ниже вашего порога остаются на последней поддерживавшей их сборке
Отсрочка: в Play Console можно запросить дополнительное время, обычно до 1 ноября
Подготовка**: читайте behaviour changes с первого developer preview, заранее поднимайте compileSdk, тестируйте с флагами совместимости в настройках разработчика и проверяйте сторонние SDK, потому что они часто отстают
Попутные дедлайны: например, поддержка страниц памяти 16 КБ для нативных библиотек, обязательная для обновлений с таргетом Android 15+ с ноября 2025 года
Staged rollout в Play отдаёт релиз проценту пользователей, который вы поднимаете вручную; phased release у Apple растягивает обновление на семь дней по фиксированному графику. Остановка или пауза не даёт обновиться новым пользователям, но никогда не убирает сборку с уже обновившихся телефонов.
Проценты в Play: любое значение, повышается, когда метрики в порядке; чтобы остановить, сделайте halt, а потом возобновите с новым процентом или замените релиз
Halt в Play: необновившиеся пользователи и новые установки остаются на предыдущем релизе; обновившиеся остаются с плохой сборкой
График Apple: 1, 2, 5, 10, 20, 50, 100% пользователей с включёнными автообновлениями; любой может обновиться вручную из стора в первый же день
Управление у Apple: пауза в сумме до 30 дней, возобновление или выпуск для всех; своих процентов нет
Что смотреть: частоту крашей и ANR для нового versionCode и свежие оценки перед каждым шагом
Ни то ни другое не откат: обновившимся поможет только новая сборка с большим номером версии или серверный переключатель
Вы заранее запрашиваете ReviewInfo у ReviewManager и вызываете launchReviewFlow в естественной паузе; Play сам решает, показывать ли диалог, по скрытой квоте и никогда не сообщает, поставил ли пользователь оценку.
Квота: не раскрывается и зависит от времени, так что вызов может ничего не показать; кнопке «Оцените нас» нужен запасной вариант (открыть страницу в сторе)
Нет результата: задача завершается одинаково, показался ли диалог, оценил ли пользователь или закрыл его; продолжайте сценарий в любом случае
Политика: никаких вопросов вроде «Вам нравится приложение?» перед диалогом, чтобы отправлять в него только довольных, и никаких наград за отзывы
Когда: после завершённого действия, например доставленного заказа или пройденного уровня, а не при запуске и не посреди сценария
Тестирование: диалог появляется только у приложения, установленного из Play: используйте internal app sharing или internal testing, а в юнит-тестах берите FakeReviewManager
iOS: requestReview тоже ограничен системой (три показа за 365 дней)
Большинство отказов не про код: ревьюер не может войти, метаданные не совпадают с приложением, разрешение или сбор данных не задекларированы, или цифровые товары продаются в обход биллинга стора. Чек-лист, прогнанный на релизной сборке, ловит почти все такие случаи.
Ревьюер не может войти: нет данных или они не работают в App access (Play) или App Review Information (Apple); дайте аккаунт без OTP, который работает не только из вашей сети
Чувствительные разрешения: QUERY_ALL_PACKAGES, MANAGE_EXTERNAL_STORAGE, SMS и журнал звонков, фоновая геолокация требуют в Play декларации и основного сценария использования
Расхождение с Data safety или privacy label: SDK собирает то, чего нет в форме
Нет удаления аккаунта: оба стора требуют удалять созданный в приложении аккаунт из самого приложения, а Play ещё и ссылку на веб
Цифровые товары мимо биллинга стора: правило Apple 3.1.1 и политика Payments в Play, кроме регионов, где разрешены альтернативы
Сломанное или недоделанное приложение: краши на устройстве ревьюера, заглушки, мёртвые ссылки (Apple 2.1); в Play сначала читайте pre-launch report с тестового трека
Вводящие в заблуждение метаданные: скриншоты несуществующих функций, названия конкурентов в ключевых словах (Apple 2.3)
Сначала воспроизведите то, что видел ревьюер, на той самой отправленной сборке и с новым аккаунтом: большинство «неправильных» отказов объясняется тем, что ревьюер не смог добраться до функции. Затем ответьте в треде ревью с доказательствами и подавайте формальную апелляцию, только если это не помогло.
Читайте, что увидел ревьюер, а не только номер правила: Apple прикладывает скриншоты, устройство и версию ОС; письмо Play называет политику и часто конкретный элемент
Почините путь ревьюера: рабочие демо-данные и пронумерованные шаги до функции решают больше отказов, чем изменения в коде
Apple: ответ в App Store Connect: ответьте в сообщениях App Review с коротким видео экрана; новый бинарник перезапускает очередь с другим ревьюером
Apple: App Review Board: отдельная форма апелляции, это медленнее, чем исправить и отправить заново
Play: апелляция со страницы Policy status: или отправьте исправленное обновление
Готовьте исправление параллельно: если ревьюера устроит небольшое изменение, это часто быстрее, чем выиграть спор
Play возвращает данные только по активным продуктам того же applicationId, под которым запущена сборка, и только если сборка с Billing Library загружена в трек; нужен также платёжный профиль.
Статус продукта: продукт в статусе Draft или Inactive не возвращается; активируйте его в Play Console
Сборка и тестировщик: сборка должна быть загружена в трек, а тестировщик должен быть license tester, установившим приложение с этого трека
Не тот пакет: debug-сборка с applicationIdSuffix запрашивает у Play продукты другого приложения
Обрабатывайте пустой ответ: показывайте ошибку с кнопкой «Повторить», а не пустой пейвол; ревьюеры отклоняют пейвол, который ничего не делает
Аналог у Apple: должен быть активен Paid Apps Agreement, а первый продукт прикреплён к версии приложения; продукты в статусе Missing Metadata дают пустой массив из Product.products(for:)
Храните минимальную поддерживаемую версию на сервере и проверяйте её при запуске; на Android Play In-App Updates API затем может установить обновление через immediate-сценарий. В iOS такого API нет, поэтому приложение показывает блокирующий экран со ссылкой в App Store.
Порог с сервера: Remote Config или свой API; проверка должна попасть в одну из первых версий, потому что в уже выпущенную сборку новый гейт не добавить
Immediate и flexible: immediate занимает весь экран и перезапускает приложение; flexible качает в фоне, а вы вызываете completeUpdate(), когда удобно
Приоритет и «устаревание»: inAppUpdatePriority (0–5) задаётся для релиза через Publishing API и читается через updatePriority(); clientVersionStalenessDays() позволяет перейти от flexible к immediate
Play должен предложить обновление: установки не из Play, остановленная раскатка или раскатка на 5%, ещё не дошедшая до пользователя, ничего не получат; показывайте свой экран со ссылкой на стор
Не запирайте пользователей: если новая сборка подняла minSdk, старые устройства никогда не обновятся; исключайте их по версии ОС или держите старый API
iOS: сравнивайте с серверным порогом и открывайте itms-apps://apps.apple.com/app/id…; iTunes lookup API кешируется и отстаёт в день релиза
Ни один стор не может удалить или откатить сборку, уже установленную на телефоны, поэтому первый час уходит на то, чтобы остановить новый ущерб (серверный переключатель, остановка раскатки), пока хотфикс с большим номером версии проходит ревью.
Первый час
Удалённый переключатель: единственный рычаг, который дотягивается до телефонов с плохой сборкой; при краше на запуске он помогает, только если флаг читается до падающего кода
Play: остановите релиз (halt), чтобы новые установки получали предыдущий; когда исправление выйдет, app recovery в Play Console позволяет показать запрос на обновление пользователям, застрявшим на плохом versionCode
App Store: поставьте phased release на паузу, если он ещё идёт; Remove from Sale лишь скрывает страницу и никак не влияет на установленные приложения
Хотфикс
Номера только растут: новый versionCode и номер сборки; предыдущую сборку заново опубликовать нельзя
Expedited review: форма Apple для критической ошибки может поднять отправку в очереди, но это одолжение, а не план: сборку всё равно могут отклонить, а в Play аналога нет
Сделайте его срочным: выставьте inAppUpdatePriority 5 для релиза в Play, чтобы гейт in-app update перешёл в immediate
Что должно было существовать
Kill switch вокруг рискованных функций, с безопасными значениями по умолчанию для сборки, которая не может получить конфиг
Поэтапная раскатка с контролем частоты крашей по versionCode до выхода на 100%
Заскриптованные действия в сторах: halt и пауза через Play Developer API и App Store Connect API, отрепетированные до инцидента
Отклонение, удаление, блокировка и закрытие аккаунта означают разные состояния с разными выходами: удалённое приложение возвращается после исправленного обновления, блокировка требует апелляции и считается страйком, а закрытие аккаунта убирает все его приложения.
Состояния
Rejected: заблокировано одно обновление; текущая версия продолжает раздаваться
Removed: приложение исчезает из стора, установленные копии работают; исправьте проблему и отправьте обновление
Suspended: удаление плюс страйк; несколько страйков или одно серьёзное нарушение ведут к закрытию аккаунта
Восстановление
Прочитайте уведомление: в нём названа политика и часто конкретный элемент: разрешение, SDK, скриншот. Исправьте именно это, затем отправьте заново или подайте апелляцию со страницы Policy status
Никогда не отправляйте без изменений: и не заводите второй аккаунт в обход; Play связывает аккаунты и закрывает оба
Apple: аналогичная апелляция идёт в App Review Board
Что должно было существовать
Общее владение: владельцем аккаунта выступает корпоративная учётка с запасными админами, а не логин одного человека
Play App Signing: потеря ключа загрузки превращается в сброс ключа, а не в новую страницу с нулём установок
Мониторинг: установки и сообщения о политиках из Play Console на дашборде, который кто-то смотрит, и канал связи с пользователями вне стора
Относитесь к каждой политике как к зависимости с фиксированной датой: направьте анонсы в общий ящик, в день публикации превращайте каждый в задачу с владельцем и выпускайте изменение минимум за два релиза до дедлайна.
Откуда они приходят: входящие и policy updates в Play Console, блог Android Developers, Apple Developer News и сообщения App Store Connect; по умолчанию их получает только владелец аккаунта
Предсказуемые: target API level в Play каждое 31 августа и минимальные Xcode и SDK у Apple каждую весну; ставьте их в календарь за год
Два вида: одни блокируют новые загрузки (target API, страницы 16 КБ), другие касаются уже опубликованных приложений (Data safety, удаление аккаунта) и могут привести к удалению приложения
SDK тоже в счёт: SDK рекламы, аналитики и платежей требуют обновления почти к каждому дедлайну и часто выпускают его поздно; отслеживайте их версии в том же реестре
Оставляйте запас на ревью: изменения ради соответствия тоже отклоняют; выпуск за два релизных цикла оставляет место для второй попытки
Свежий пример: Android developer verification: с сентября 2026 года приложения на сертифицированных устройствах в Бразилии, Индонезии, Сингапуре и Таиланде должны быть от подтверждённых разработчиков, даже вне Play