React Native: от создания проекта до App Store и Google Play
Написание самого приложения планируют все. А сроки запуска срываются на подписании, тестовых треках, формах о приватности и ревью в магазинах. Вот путь, которым я иду от пустого репозитория до обоих магазинов.
Я делаю приложения на React и React Native больше семи лет и провёл несколько из них через ревью App Store и Google Play. Среди них — мобильное банковское приложение для Молдовы с интеграциями MAIB и MPass и подписками через RevenueCat, а также приложение для знакомств; оба я делал как сотрудник или подрядчик компаний, которым они принадлежат. В Syncra мы сейчас делаем собственное мобильное приложение — iBeep. Оно ещё в разработке, и в магазинах его пока нет.
Запуск редко задерживает код. Его задерживает всё, что вокруг кода: подписание, тестовые треки, декларации о приватности, ревью и первое обновление после релиза. Ниже — путь, которым я иду, по порядку.
1. Начните с Expo и рано переходите на development builds
Для нового приложения на React Native я по умолчанию беру Expo. Документация React Native сама рекомендует начинать с фреймворка, и Expo — тот, которым пользуется большинство команд. Он даёт разумную структуру проекта, файловый роутинг, большой набор поддерживаемых нативных модулей и сервис сборки.
На старте важны два решения:
- Используйте development builds, а не Expo Go, как только добавляете нативный модуль, которого нет в Expo Go. Development build — это ваше собственное приложение с меню разработчика, и там, где это важно, оно ведёт себя как продакшен-версия.
- Пусть нативные проекты генерирует Expo. С prebuild папки
iosиandroidгенерируются из конфигурации приложения, а нативные изменения проходят через config plugins. Обновление превращается в правку конфига, а не в конфликт слияния в проекте Xcode.
Полностью переходить на bare-проект приходится редко. Собственный нативный код всё равно вписывается — в виде модуля Expo или локального config plugin.
2. Стройте репозиторий в расчёте на несколько приложений
Мобильное приложение редко живёт само по себе. Есть API, админка, часто лендинг. Когда всё это лежит в одном монорепозитории, у них могут быть общие типы, схемы валидации и константы, а изменение контракта API проявляется как ошибка типов в приложении, а не как падение в продакшене.
iBeep устроен именно так: монорепозиторий на Turborepo, где рядом лежат приложение на Expo, API и лендинг. Держите границы чёткими. В общих пакетах — типы и чистая логика и никогда не код React Native, который пришлось бы устанавливать серверу.
3. Разделите окружения с первого дня
Настройте три варианта до того, как они понадобятся: development, preview и production. Дайте каждому свой bundle identifier и своё название приложения, чтобы все три могли стоять на одном телефоне, не перезаписывая друг друга. Для этого достаточно динамического app.config.ts, который читает переменную APP_VARIANT.
Одно правило стоит повторять всей команде: всё, что попадает в бандл приложения, публично. Переменные с префиксом EXPO_PUBLIC_ вкомпилируются в JavaScript, который уходит на каждый телефон. Секретам API место на вашем сервере, а приложение общается с сервером.
4. Настройте подписание один раз и как следует
Именно на подписании при первом запуске теряют дни.
- iOS требует членства в Apple Developer Program, сертификата для дистрибуции и provisioning-профилей. EAS может создать их и управлять ими за вас — я это рекомендую, если нет причин поступить иначе.
- На Android ключей два. При Play App Signing ключ, которым подписывается то, что устанавливают пользователи, хранит Google, а у вас остаётся ключ загрузки (upload key). Сделайте его резервную копию. Если потеряете — можно запросить сброс, но время вы потеряете.
- Тщательно выбирайте bundle identifier и имя пакета. Они постоянны. Приложение можно переименовать, но сменить его идентификатор нельзя.
Версия на каждой платформе состоит из двух чисел: версии, которую видят люди, и номера сборки, который должен расти с каждой загрузкой. Пусть номер сборки увеличивает сервис сборки, чтобы два человека никогда не загрузили один и тот же.
5. Как можно раньше ставьте сборки на реальные телефоны
Симуляторы скрывают проблемы, которые действительно важны: медленные устройства, реальные сети, уведомления, диплинки, запросы разрешений. Сборки должны оказаться на реальных телефонах в первые недели, а не в последние.
- TestFlight доставляет сборку внутренним тестировщикам через несколько минут после её обработки.
- Трек внутреннего тестирования Google Play делает то же самое на Android.
Отдельно заложите в план одно правило Google Play. Новый личный аккаунт разработчика должен провести закрытое тестирование минимум с 12 тестировщиками, которые остаются в тесте непрерывно не менее 14 дней, и только после этого может подать заявку на доступ к продакшену. Эти две недели в конце не сожмёшь, поэтому начинайте заранее или публикуйтесь с аккаунта организации, на который это правило не распространяется.
6. Заполните формы, которые блокируют запуск
Оба магазина спрашивают, какие данные собирает приложение и зачем, и оба это проверяют.
- Декларации о приватности. Раздел App Privacy у Apple и форма Data safety в Google Play должны соответствовать тому, что на самом деле собирают приложение и каждый SDK в нём: аналитика, отчёты о сбоях, реклама, аутентификация. Составьте список SDK, прежде чем браться за любую из форм.
- Удаление аккаунта. Если в приложении можно создать аккаунт, Apple требует, чтобы удаление аккаунта можно было начать прямо из приложения. Google Play требует путь внутри приложения и веб-ссылку, по которой можно запросить удаление. Делайте это полноценной функцией, а не письмом в поддержку.
- Privacy manifests на iOS. Apple требует их для определённых системных API, а многие SDK эти API используют. Обычно достаточно держать SDK в актуальном состоянии.
- Вход через соцсети. Если вы предлагаете вход через сторонний сервис, Apple, как правило, требует добавить и равноценный вариант, ориентированный на приватность. На практике это обычно Sign in with Apple.
- Платежи. Цифровые товары и подписки, которые используются внутри приложения, как правило, должны проходить через систему встроенных покупок каждого магазина. Правила различаются по регионам и в последнее время меняются, так что сверяйтесь с актуальными требованиями для тех рынков, на которых запускаетесь. Сервис подписок вроде RevenueCat избавляет от необходимости самому писать валидацию чеков для двух магазинов.
7. Подготовьтесь к ревью
Большинства отказов можно избежать: падение на устройстве ревьюера, логин без демо-аккаунта, контент-заглушки, метаданные, обещающие функции, которых в приложении нет, или декларация о приватности, которая не совпадает с приложением.
Напишите для ревьюеров заметки, объясняющие всё неочевидное, приложите рабочий демо-аккаунт и заложите на первую отправку несколько дней запаса. Последующие ревью обычно проходят быстрее, но вопросы возникают именно на первой отправке.
8. Спланируйте первое обновление до запуска
Выкатить исправление придётся в первые же дни после запуска. Заранее знайте, как вы это сделаете.
- Изменения в JavaScript и ассетах можно выпускать как обновления по воздуху (OTA), например через EAS Update, без нового ревью в магазине. Привязывайте каждое обновление к runtime version, чтобы JavaScript никогда не попал в нативный бинарник, под который он не собирался. Используйте такие обновления для исправлений и улучшений. Магазины ожидают, что приложение, которое устанавливают люди, остаётся тем самым приложением, которое прошло ревью.
- Нативные изменения — новый нативный модуль, разрешение или обновление SDK — требуют новой сборки для магазина.
- Раскатывайте постепенно. Phased release в App Store и staged rollouts в Google Play позволяют сначала выпустить версию на часть пользователей и остановиться, если растёт число сбоев.
Следите за требованиями платформ. Google Play каждый год поднимает минимальный target API level, а Expo выпускает новые SDK несколько раз в год. Небольшие регулярные обновления обходятся намного дешевле, чем одно большое раз в два года.
Короткий чеклист перед отправкой
- Bundle identifier и имя пакета утверждены, все три варианта приложения работают.
- Подписание настроено, резервная копия ключа загрузки сделана.
- Тестирование на реальных устройствах на обеих платформах, включая медленный Android-телефон.
- Закрытое тестирование запущено заранее, если оно требуется для вашего аккаунта Google Play.
- Декларации о приватности учитывают каждый SDK, удаление аккаунта встроено.
- Заметки для ревьюеров и демо-аккаунт готовы.
- Отчёты о сбоях работают, а способ выпуска обновлений проверен до первого дня.
Как мы работаем в Syncra
Мы проводим мобильные приложения от пустого репозитория до обоих магазинов и поддерживаем их после запуска: React Native и Expo, бэкенд за ними и вся описанная выше работа с магазинами. iBeep, наше собственное приложение, проходит тот же путь. Когда iBeep появится в магазинах, вы найдёте его на этом сайте.