Скриншоты Expo App Store: почему EAS Submit их пропускает и как всё-таки их подготовить (2026)
.ipa/.aab в App Store Connect и Play Console — и этим ограничивается. Он не генерирует, не загружает и не управляет скриншотами магазина. Поэтому Expo-разработчикам нужен отдельный пайплайн для скриншотов: захват кадров из dev/preview-сборки (симулятор, эмулятор или Maestro/Detox), а затем компоновка и локализация маркетинговых панелей. В этой статье честно разобраны команды для захвата, а также где в эту схему вписывается инструмент компоновки — сам он ничего не захватывает.Если ты публикуешь Expo-приложение, релизный путь, скорее всего, заканчивается одной командой: eas submit. Она берёт собранный EAS бинарник и передаёт его Apple или Google. Чисто, предсказуемо, надёжно. Потом открываешь App Store Connect, чтобы сделать сборку активной — и видишь пустые слоты для скриншотов. Каждый раз.
Многих это застаёт врасплох, потому что EAS создаёт ощущение, что делает всё. Собирает, подписывает, отправляет. Неужели со скриншотами тоже? Нет — и документация прямо об этом говорит. Это не баг и не недостающая функция, на которую можно жаловаться — просто это не входит в задачи EAS Submit.
Что EAS Submit делает (и чего не делает)
EAS Submit — это сервис доставки бинарников. Он загружает ровно одно: скомпилированный архив приложения — .ipa для iOS, .aab для Android — в пайплайн обработки магазина. Документация Expo чётко обозначает границу:
«EAS Submit загружает бинарник, но не управляет метаданными листинга магазина, скриншотами или примечаниями к релизу.»
Есть сопутствующий инструмент — EAS Metadata, который умеет автоматизировать часть листинга App Store: название приложения, подзаголовок, локализованные описания, ключевые слова, ссылки на поддержку — из конфиг-файла. Он действительно полезен и стоит того, чтобы его настроить. Но прочитай его scope внимательно: скриншотов там нет. EAS Metadata пушит текст, не изображения. Скриншоты в обоих магазинах по-прежнему твоя забота.
Таким образом, проблема скриншотов в Expo распадается на две отдельные задачи — и полезно держать их в голове раздельно:
- Захват — получить сырые кадры реальных экранов приложения из сборки.
- Компоновка и локализация — превратить сырые кадры в оформленные, подписанные, многоязычные маркетинговые панели, которые магазины реально показывают.
EAS не делает ни того ни другого. Собственное руководство Expo по ассетам магазина предлагает захватывать кадры самостоятельно и оформлять панели в таком инструменте, как Figma. Разберём обе задачи с конкретными командами.
Задача 1: захват кадров из dev- или preview-сборки
Нужны скриншоты реального приложения — значит, приложение должно где-то работать и его нужно захватить. Для Expo это dev-клиент или preview-сборка — не Expo Go, потому что Expo Go показывает обёртку Expo и нативная конфигурация может отличаться. Собирай и запускай локально стандартными командами Expo:
npx expo run:ios— пребилдит нативный iOS, компилирует и запускает приложение в iOS Simulator.npx expo run:android— то же самое для Android-эмулятора (или подключённого устройства).
Когда приложение открыто в iOS Simulator, захват — одна команда в терминале Mac:
xcrun simctl io booted screenshot home.png
booted адресуется к текущему запущенному симулятору и записывает попиксельно точный PNG в рабочую директорию. Два флага важны для работы с магазином: --type=png (по умолчанию, и именно это нужно магазинам) и --mask=ignored против --mask=black — маска управляет тем, рендерятся ли вырез и скруглённые углы в изображение. Для загрузки в App Store обычно нужны плоские прямоугольные пиксели — рамку устройства добавишь позже при компоновке, так что захват без маски — как правило, правильная отправная точка.
На Android захватывай прямо с эмулятора (или устройства) через adb:
adb exec-out screencap -p > home.png
Используй exec-out, а не shell screencap. Обычный shell-путь пропускает PNG через псевдотерминал, который на некоторых конфигурациях искажает бинарник (получаешь повреждённый файл с лишними символами возврата каретки); exec-out передаёт байты напрямую и работает надёжно. Если запущено несколько эмуляторов, адресуйся к конкретному через adb -s <serial> из adb devices.
Вот и весь набор для ручного захвата: две команды, по одной на платформу, без зависимостей помимо Xcode и Android SDK, которые у тебя уже есть для нативной сборки Expo.
Задача 1, автоматизированная: Maestro или Detox
Вручную переходить к нужному экрану и запускать команды нормально для небольшого числа кадров. Но когда у тебя восемь экранов для двух классов устройств или нужно пересоздавать скриншоты при каждом релизе, чтобы они не расходились с реальным UI — автоматизируй захват с помощью end-to-end инструмента тестирования, который умеет управлять приложением и делать снимки.
Maestro — тот инструмент, к которому сам Expo обращается в задокументированных примерах EAS Workflows. Флоу пишутся на простом YAML, порог входа низкий. Флоу, который доводит приложение до нужного экрана и делает снимок, выглядит так:
appId: com.you.yourapp --- - launchApp - tapOn: "Get started" - assertVisible: "Your dashboard" - takeScreenshot: dashboard
Запускается командой maestro test flows/home.yaml. Команда takeScreenshot записывает PNG в директорию вывода тестов (укажи MAESTRO_TESTS_DIR в нужное место). Те же флоу работают в CI на EAS Workflows — задокументированный пример Expo собирает .apk с профилем сборки e2e-test и затем запускает флоу из .maestro/ против него — так что захват скриншотов можно подключить к той же задаче, что выполняет e2e-тесты.
Detox — ещё один проверенный вариант, с более строгим и программным JavaScript API:
const path = await device.takeScreenshot('dashboard');
Будь честен с собой насчёт настройки Detox с Expo. Detox официально не поддерживает Expo. На практике это работает, если выполнить npx expo prebuild для генерации нативных проектов и собрать release-стайл клиент (не dev-клиент) со встроенным JS-бандлом — затем навести Detox на этот бинарник. Движущихся частей больше, чем в YAML-флоу Maestro, а выигрыш — более строгая синхронизация и assertion API Detox. Если Detox уже используешь — задействуй его для захвата; если выбираешь с нуля и цель — скриншоты магазина, Maestro — более лёгкий путь.
Задача 1, вручную: правильный выбор для редких релизов
Автоматизация окупается, когда выпускаешь часто. Если у тебя один-три релиза в год — а это большинство инди Expo-приложений — настройка Maestro-флоу или Detox-конфига ради захвата скриншотов стоит усилий, которые едва ли отобьются. При такой периодичности просто:
- Запусти сборку командой
npx expo run:ios/run:android, наполни её реалистичными демо-данными. - Перейди к каждому ключевому экрану вручную.
- Сними каждый командой
simctl/adbвыше.
Двадцать минут кликов лучше, чем полдня над тестовым окружением, о котором ты забудешь к следующему релизу. Ничего зазорного в ручном захвате — магазины не знают, как был сделан PNG.
Задача 2: компоновка и локализация на 50 языков
Вот та часть, которую инструменты захвата намеренно не затрагивают — и именно по ней магазины тебя оценивают. Сырой PNG из simctl — это UI твоего приложения на белом фоне. То, что поднимает позиции в поиске и конвертирует на странице продукта, — это маркетинговая панель: скриншот в рамке устройства, на брендовом фоне, с однострочной подписью, объясняющей, зачем этот экран важен — обычно в виде многопанельной карусели, читающейся слева направо. А в App Store скриншоты локализуются по размеру устройства и по языку, так что серьёзный запуск — это десятки вариантов, а не пять.
Именно здесь в схему вписывается Mokbi — и стоит чётко обозначить границу. Mokbi не захватывает приложение — исходные кадры ты по-прежнему делаешь командами Expo выше. Он берёт эти кадры и позволяет тебе прямо в браузере: помещать их в настоящие рамки устройств, добавлять подписи и градиентные фоны, выстраивать многопанельные карусели, переводить тексты подписей на 50 языков одним кликом и пакетно экспортировать во всех размерах App Store и Play Store за один проход. Дизайн бесплатен с водяным знаком предпросмотра; безлимитный экспорт доступен по подписке — Solo €29.99/mo (1 приложение) или Studio €49.99/mo (до 5 приложений), без разовой покупки. Он заменяет шаг с шаблоном Figma, который руководство Expo вскользь упоминает — не больше и не меньше.
Реалистичный совмещённый воркфлоу
- Собери dev/preview-клиент.
npx expo run:iosиnpx expo run:android, наполни хорошими демо-данными. - Захвати исходные кадры. Вручную через
xcrun simctl io booted screenshotиadb exec-out screencap -p, или автоматически через MaestrotakeScreenshot/ Detoxdevice.takeScreenshot— в идеале на EAS Workflows, чтобы пересоздавались при каждом релизе. - Скомпонуй маркетинговые панели. Добавь рамки устройств, подписи и оформи карусель из сырых кадров.
- Локализуй и пакетно экспортируй. Переведи подписи на нужные языки, экспортируй во всех требуемых размерах для обоих магазинов.
- Загрузи ассеты листинга. Скриншоты в App Store Connect и Play Console; если используешь EAS Metadata — дополни текстовые поля с его помощью.
- Отправь бинарник.
eas submit— единственный шаг, который EAS действительно берёт на себя. - Следующий релиз: перезахвати изменившиеся экраны, открой сохранённый проект компоновки, замени кадры, переэкспортируй. Подписи и переводы остаются на месте.
Когда можно обойтись без автоматизации
Maestro или Detox для захвата стоит использовать, когда расхождение скриншотов — реальная проблема: выпускаешь еженедельно, UI меняется постоянно или поддерживаешь много приложений и не можешь позволить себе устаревшие ассеты магазина. В таких случаях пересоздание кадров в CI окупается — и история с инструментами для скриншотов React Native (которую Expo наследует) стоит изучить.
Всем остальным — тем, кто выпускает раз в квартал — автоматизация не нужна. Ручной захват двумя командами в терминале, затем браузерная компоновка и локализация — и к вечеру у тебя готовый, многоязычный листинг с нулём зависимостей между релизами. Подбирай инструменты под свой ритм, а не под то, что красиво смотрится на CI-дашборде.
Бинарная часть в любом случае решена: eas submit её берёт на себя. Перед загрузкой проверь скриншоты на соответствие актуальным требованиям магазина — Apple отклоняет заявку из-за одного пикселя погрешности — а остальное в запуске — это просто дизайн.