Публикация в RuStore: пять шагов формы, отказ по юридическому основанию и почему APK нужно вскрывать, а не грепать

Как ЧатЯдро попало в RuStore за девять дней: что скрывают поля консоли, за что отказали на модерации, как собрать сборку без своего апдейтера и как правильно проверять, что внутри APK.

ЧатЯдро подано в RuStore 7 августа 2026, отклонено 11-го, пересобрано в тот же вечер и опубликовано 16-го. Ниже — что именно пришлось узнать по дороге. Документация магазина в день подачи отдавала 429, так что половина лимитов выяснилась только в живой форме.

Форма подачи: пять шагов и их ловушки

Загрузка версии в консоли RuStore — это пять экранов: Файлы → Безопасность → Информация → Медиафайлы → Параметры публикации. Проходили их по одному, с проверкой каждого поля, и ни разу не пришлось возвращаться. Что стоит знать заранее:

Файлы. Комментарий для модератора ограничен 180 символами. Заготовленный текст на тысячу знаков не влез. Единственное, что туда действительно нужно уместить, — данные тестового входа. Всё остальное уходит в «Обоснование» на следующем шаге, где места 1500. Подпись для AAB не нужна, если грузите APK.

Безопасность. «Типы собираемых данных» — 38 чекбоксов, мы отметили 17. Разрешения консоль вытаскивает из APK сама и показывает списком. Обоснование чувствительных разрешений — до 1500 символов.

Информация. Краткое описание — 80 символов, полное — 4000. Категории «Социальные сети» в RuStore нет вообще; из двадцати доступных единственный честный вариант для платформы сообществ — «Общение». Поисковые теги — только из готового списка, свои слова вписать нельзя, максимум пять. Вторую категорию сознательно не ставили: любая дополнительная обещает то, что у нас работает только внутри сообщества, а это путь к плохим отзывам на старте.

Медиафайлы. Иконка 1:1, до 512 пикселей. Скриншотов от трёх до десяти, и ориентацию всей витрины задаёт первый файл. Видео нельзя загрузить файлом — только ссылкой на VK Видео. Полей два, и их легко перепутать: верхнее «Видео» принимает 16:9 и 9:16, а «Фоновое видео для карточки» — только горизонтальное, и вертикальную ссылку отвергает невнятным «Проверьте правильность ввода». Мы на этом месте сначала решили, что магазин вообще не принимает клипы. Принимает, просто не в том поле.

Параметры публикации. «Автоматически, сразу после одобрения», если релиз не привязан к дате.

Отдельная деталь про тестовый аккаунт для модератора. Его лучше завести заранее и проверить вход, потому что на бэкенде стоит лимит попыток входа с одного IP. Модератор, упёршийся в него, решит, что приложение не работает.

Отказ 11 августа

Модератор написал: для публикации нужно быть зарегистрированным в реестре операторов персональных данных, подтверждение — на почту поддержки. Само приложение при этом не смотрели.

Формально это был не отказ приложению, а запрос документа: в реестре мы были с 24 июля, за две недели до подачи, просто в консоли нет поля, куда это вписать. Отправили выписку из реестра и скриншот проверки статуса. Побочная находка: поиск по реестру Роскомнадзора по ИНН физлица ничего не находит, работает только прямая ссылка на запись.

Поддержка подтверждение приняла и попросила отправить приложение повторно. И тут второе правило магазина: тот же versionCode повторно не принимается. Пришлось собирать новую версию.

Пересборка из боевого коммита

Проблема в том, что за четыре дня в бете накопились правки, которые ни разу не собирались в релизный APK. Тащить их в магазин вслепую не хотелось. Решение: отдельная рабочая копия (git worktree) на боевом коммите, в ней поднят только номер версии, и из неё собрана сборка 462. Набор разрешений проверен и совпал с 461 один в один.

Сама сборка для магазина отличается от обычной четырьмя вещами, и они зашиты в отдельный скрипт:

  1. --dart-define=DISTRIBUTION=rustore отключает собственный апдейтер. Обновления в магазине ставит магазин, а свой механизм обновления внутри — известная причина отказов на модерации.
  2. Из манифеста вырезается REQUEST_INSTALL_PACKAGES: у модератора закономерный вопрос, зачем приложению право устанавливать другие приложения.
  3. Версия не поднимается автоматически, иначе номера в магазине и на сайте разойдутся.
  4. Веб не собирается: RuStore принимает только APK.

Две ловушки в самом скрипте. Первая: без flutter clean Flutter может взять из кэша Dart-код, собранный без флага, то есть с живым апдейтером внутри, и снаружи это не видно. Вторая: папку build/ сносит любая следующая сборка. Собранный для магазина APK однажды был стёрт сборкой беты через полчаса. Теперь скрипт сразу копирует файл наружу и кладёт рядом sha256.

Как проверять APK: не grep

За час до подачи я дважды ошибся одинаково — искал строки внутри libapp.so и делал из находки вывод.

Первый раз искал версию 1.8.74 (461) и не нашёл: чуть не объявил сборку испорченной. На деле версия собирается в рантайме из двух констант, целой строки в файле нет. Второй раз вытащил из APK все строки вида android.permission.*, увидел DUMP и предложил его убирать. Оказалось, это не запрошенное разрешение, а защита нашего же компонента: атрибут android:permission у приёмника AndroidX ProfileInstaller. В том же разборе я пропустил два настоящих разрешения.

Правильные инструменты:

Что проверяем Чем
Версия, имя пакета aapt2 dump badging app.apk, строка package:
Запрошенные разрешения uses-permission из объединённого манифеста в build/…/merged_manifest/, разбором XML, не grep: бывают многострочные теги и maxSdkVersion
Кто добавил разрешение manifest-merger-release-report.txt
Отключён ли апдейтер по отсутствию строк, которые есть только в обычной сборке: адрес version.json и имя файла обновления. Компилятор выбрасывает мёртвый код вместе с адресами
Иконка вскрытием, по размеру ресурса

Ключевое различие, которое я тогда не держал в голове: <uses-permission android:name="X"> значит «прошу право X», а android:permission="X" внутри <receiver> или <service> значит «до меня можно достучаться, только имея X». Второе у пользователя не спрашивается и в карточке магазина не показывается.

И общее правило: если проверка дала неожиданный результат, сначала усомниться в проверке, и только потом в сборке.

После публикации

Модерацию прошли 16 августа. Больше половины новых участников в следующие дни пришли из магазина, без рекламы: это видно по версии сборки в журналах сервера.

Есть и обратная сторона: люди из RuStore не получают обновления с сайта, только из магазина. К началу сентября они отстали от беты на одиннадцать версий, и каждый релиз теперь нужно подавать в магазин отдельно. Форма при повторной подаче заполняется без правок, разрешения и описание остаются с прошлой версии, но модерация занимает дни.

Ещё один эффект магазина всплыл у пользователя, переустановившего приложение: Android вернул из резервной копии зашифрованные данные, а ключ шифрования выдал новый, и приложение открылось белым экраном. Лечится allowBackup="false" в манифесте и защитой на чтение хранилища.

Что бы я сделал иначе

  • Завёл бы регистрацию в реестре операторов ПД в чек-лист подачи, рядом с иконкой и скриншотами, и приложил бы выписку в комментарий модератору сразу.
  • Написал бы скрипт проверки APK до первой подачи, а не после двух ошибок.
  • Не тратил бы день на вопрос «принимает ли магазин вертикальное видео». Принимает.