Как AGP 9 сломал сборку с VK SDK и RuStore — и почему помог свой Nexus
Обновление до Android Gradle Plugin 9 обрывает сборку Flutter-приложений, которые используют VK SDK и RuStore SDK: строгая фильтрация репозиториев в AGP 9 блокирует внешние Maven-каналы VK и RuStore, если они не прописаны явно в settings.gradle. Рабочее решение — поднять приватный Nexus-репозиторий как прокси для этих источников и зафиксировать правила разрешения зависимостей вручную.
Сборка встала за девять часов до релиза в RuStore
В пятницу вечером у клиента — московской транспортной компании с автопарком корпоративных смартфонов на отечественной прошивке — был назначен релиз мобильного приложения для водителей и диспетчеров с интеграцией с 1С:Управление автотранспортом. Приложение должно было появиться в RuStore к понедельнику: одно из условий тендера на обслуживание автопарка требовало дистрибуции только через российский магазин приложений, без Google Play, потому что часть автопарка уже перешла на смартфоны с сертифицированной отечественной прошивкой. За выходные разработчик обновил Flutter до 3.47 и подтянул рекомендованную версию Android Studio — та без лишних вопросов поставила Android Gradle Plugin 9. Следующий пуш в CI вернул красную сборку.
Лог ругался на разрешение зависимостей ru.rustore.sdk и com.vk.id — Gradle не находил их, хотя они лежали в проекте месяцами и собирались без единой жалобы. До дедлайна оставалось девять часов, а найти причину за пять минут по логу не получалось: ошибка тонула среди сотни строк про checksum verification и content filtering, которые раньше в этом проекте никого не волновали.
Почему AGP 9 закрывает доступ к VK SDK и RuStore SDK
До девятой версии AGP прощал вольности: репозитории можно было объявлять прямо в build.gradle модуля, и Gradle перебирал их по очереди, пока не находил артефакт. AGP 9 по умолчанию переключает dependencyResolutionManagement.repositoriesMode на FAIL_ON_PROJECT_REPOS — все источники зависимостей нужно перечислить централизованно в settings.gradle, а для каждого лучше сразу задать content filtering по группе пакетов.
VK SDK публикуется в собственном Maven-репозитории VK, RuStore SDK — в отдельном фиде RuStore. Ни тот, ни другой не зеркалируются на Maven Central и не входят в google() по умолчанию. Если при переходе на AGP 9 эти адреса не добавить в централизованный список репозиториев проекта — а в документации VK и RuStore на момент выхода девятой версии AGP про неё не было ни слова, — сборка падает с ошибкой classpath, которая выглядит как проблема версии SDK, а не как проблема доступа к репозиторию.
Но у клиента история оказалась хитрее: репозитории в settings.gradle прописали ещё год назад, и раньше всё работало. Проблема вскрылась в другом месте — Gradle резолвит зависимости в порядке объявления репозиториев, и один из пакетов RuStore SDK совпал по имени с транзитивной зависимостью AndroidX. AGP 8 в такой ситуации молча брал что попадалось первым, AGP 9 останавливает сборку с явной ошибкой конфликта версий — неприятно в моменте, но по факту страхует от того, чтобы в релиз ушла не та библиотека.
Что мы перепробовали за две ночи
Первым делом откатили AGP до восьмой версии — сборка ожила за десять минут. Но следом посыпались предупреждения от самого Flutter 3.47: начиная с этой версии плагин рассчитывает на новую архитектуру Gradle, которую AGP 8 поддерживает не полностью, и часть hot-reload функций в debug-сборке отвалилась. Откат тушил один пожар и разжигал другой, а команде нужна была рабочая сборка, а не временная заплатка перед релизом.
Вторая попытка — вручную скачать нужные .aar и .jar файлы VK SDK и RuStore SDK и положить их в libs/, полностью минуя внешние репозитории. Сборка прошла. Но при первом же патче безопасности от RuStore — а обновляется их SDK чаще, чем хотелось бы, потому что магазин регулярно донастраивает пуш-уведомления и антифрод-проверки — пришлось бы вручную повторять всю процедуру, и никто в команде не хотел брать это на себя как регулярную обязанность.
Третий вариант — не убирать внешние репозитории, а поставить между CI и ними прокси, который сам решает, что откуда брать, кеширует результат и не зависит от того, ответит ли внешний Maven-фид RuStore за разумное время. Так и родилась идея переезда на собственный Nexus.
Переезд на свой Nexus: пять шагов за одну ночь
Идея простая: не бороться с внешними репозиториями VK и RuStore напрямую, а поставить между ними и CI собственный сервер, который берёт на себя кеширование, повторные попытки и контроль версий. Сделали так.
- ✓Подняли Nexus Repository OSS на отдельном сервере и открыли к нему доступ только для CI и рабочих машин команды.
- ✓Настроили два proxy-репозитория — для Maven-канала VK и для фида RuStore — с автоматическим кешированием артефактов на диске Nexus.
- ✓Собрали group-репозиторий, который объединяет эти два прокси с google() и mavenCentral(), и прописали content filtering по groupId для каждого источника, чтобы Gradle не путал одноимённые пакеты.
- ✓В settings.gradle оставили единственный адрес — свой Nexus — вместо списка из четырёх внешних репозиториев.
- ✓Зафиксировали версии VK SDK и RuStore SDK в lock-файле, чтобы новый релиз SDK не прилетал в сборку без отдельного ревью.
На всё — от установки Nexus на сервере до зелёной сборки в CI — ушло около шести часов вместо девяти, отведённых на паузу перед релизом. Помогло то, что приложение клиенту разрабатывали мы сами с нуля и знали архитектуру проекта изнутри: команде со стороны, которая видит чужой Gradle-файл впервые, на такой разбор обычно нужно больше времени.
Подобные задачи — мобильные приложения с несколькими внешними SDK и интеграцией 1С — мы ведём как разработку мобильных приложений под ключ: от архитектуры репозиториев до публикации в RuStore и Google Play.
Три варианта рядом: что теряли и приобретали в каждом
Откат AGP, ручной вендоринг файлов и свой Nexus решают одну и ту же задачу по-разному. Вот как они выглядели на практике в этом проекте.
| Вариант | Время на внедрение | Стабильность сборки в CI | Что теряли |
|---|---|---|---|
| Откат AGP до версии 8 | около 10 минут | сборка идёт, но конфликтует с новой архитектурой Gradle во Flutter 3.47 | часть hot-reload функций в debug-режиме |
| Ручной вендоринг .aar и .jar в libs/ | 2-3 часа на первичную настройку | стабильна до следующего обновления SDK | ручное обновление при каждом патче VK или RuStore |
| Свой Nexus как прокси | около 6 часов на весь переезд | стабильна, не зависит от доступности внешних Maven-фидов | расходы на сервер и его сопровождение |
| Ничего не менять, ждать патча от VK или RuStore | от нескольких дней до пары недель | сборка не идёт вовсе | сорванный срок публикации в RuStore |
Для разового проекта откат AGP или вендоринг файлов — рабочий компромисс на день-два. Но если приложение живёт годами и регулярно обновляется, как в этом случае, вложение в свой Nexus окупается уже на втором-третьем обновлении SDK: команда просто не замечает, что VK или RuStore что-то поменяли на своей стороне.
Во что могла обойтись задержка и что получил клиент
Публикация в RuStore к понедельнику была условием тендера на обслуживание автопарка: без неё компания теряла право участвовать в текущем квартале, а не просто откладывала релиз на неделю — контракт предполагал штрафные санкции за срыв сроков внедрения. Три разработчика вместо доработки функций диспетчерской части два дня разбирали логи Gradle — это те часы, которые не пошли в продукт и которые клиент, по сути, оплатил дважды: за отладку и за задержку фич.
После переезда на Nexus релиз вышел в RuStore в срок. Побочный эффект оказался приятным: сборка в CI стала идти быстрее — раннер больше не ждёт ответа от внешних Maven-фидов VK и RuStore при каждом пуше, а берёт закешированные артефакты со своего сервера. Для команды с частыми коммитами это заметно уже за первую неделю.
Когда свой Nexus нужен, а когда это лишняя инфраструктура
Не любому проекту он нужен. Если приложение использует одну внешнюю библиотеку вроде VK SDK и обновляется раз в полгода, риск упереться в такой конфликт невысок — проще пережить один аврал, чем содержать сервер ради него. Свой Nexus оправдан, когда в проекте одновременно несколько источников зависимостей за пределами Maven Central — VK, RuStore, банковские SDK для эквайринга, — а сборка идёт в CI по несколько раз в день, и простой каждого пайплайна стоит команде реального времени. Для разовой утилиты или MVP такая инфраструктура избыточна — проще смириться с одним авралом раз в год, чем содержать сервер, который простаивает большую часть времени.
Поднять и настроить такой прокси — по сути, работа системного администратора: у нас это тарифицируется от 3800 ₽/час, и для типового проекта с двумя-тремя внешними репозиториями уходит несколько часов, а не дней. Если приложение с интеграцией VK ID, RuStore и 1С разрабатывается с нуля, мы сразу закладываем такую инфраструктуру в архитектуру — это дешевле, чем чинить её постфактум за девять часов до релиза. Само приложение — от B2B-приложения с 1С для внутренних процессов до клиентского приложения с авторизацией через VK — у нас стартует от 500 000 ₽, точную сумму считаем после короткого технического интервью, полный список условий — на странице тарифов.
❓ Частые вопросы
Стоит ли сразу обновляться до AGP 9, если у приложения есть VK SDK или RuStore SDK?
Сначала проверьте сборку на отдельной ветке: убедитесь, что все внешние Maven-репозитории явно прописаны в settings.gradle с content filtering по groupId. Официальная документация VK и RuStore часто отстаёт от свежих версий AGP, поэтому конфликт стоит поймать до мержа в основную ветку, а не в ночь перед релизом.
Нужен ли свой Nexus, если в проекте используется только VK SDK без RuStore?
Не обязательно. Один внешний репозиторий редко ломает сборку так, чтобы это оправдывало содержание сервера. Свой Nexus имеет смысл, когда в проекте несколько источников зависимостей за пределами Maven Central и CI собирается по несколько раз в день, а не раз в месяц.
Сколько стоит настроить приватный Nexus-репозиторий для мобильного проекта?
Настройка прокси-репозитория и content filtering — это работа сисадмина, у нас она тарифицируется от 3800 ₽/час. Для типового проекта с двумя-тремя внешними Maven-источниками уходит несколько часов на первичную настройку. Итоговая сумма зависит от количества внешних SDK и от того, нужен ли отдельный сервер под Nexus.
Что делать, если сборка приложения упала за день до обязательного релиза в RuStore?
Сначала проверьте лог на ошибки разрешения зависимостей, а не только на синтаксис кода — часто дело в репозиториях, а не в самом коде. Если своими силами разобраться не успеваете, можно подключить внешнюю команду для экспресс-диагностики build.gradle и settings.gradle, чтобы успеть выпустить релиз в срок.
Ломает ли обновление Flutter до 3.47 совместимость с уже интегрированным 1С-бэкендом?
Напрямую нет — Flutter работает с 1С через REST или HTTP-сервисы, и версия фреймворка на этот протокол не влияет. Ломается обычно сборка Android-части из-за смежных обновлений AGP и Gradle. Проверять стоит именно Android-сборку после апдейта, а бэкенд на 1С трогать не придётся.
Или позвоните: +7 906 045-28-27 — в рабочее время с 9:00 до 19:00
Остались вопросы? Нужна помощь?
Менеджеры компании с радостью ответят на ваши вопросы, произведут расчет стоимости услуг и подготовят индивидуальное коммерческое предложение.
Бесплатная консультация

