Введение
«Что такое Dynamic Feature Module и зачем он нужен?» — вопрос, после которого кандидаты с опытом 1–2 года обычно замолкают. App Bundle большинство хоть раз видело в Play Console, а вот feature-модули, on-demand доставка и Play Feature Delivery — это уже тёмный лес.
Тема доставки — одна из самых недооценённых при подготовке. Код писали, экраны верстали, а вот как приложение попадает на устройство и почему Google Play требует загружать AAB, а не APK, — объяснит не каждый. При этом это гарантированные вопросы на собеседованиях в сильные компании: они быстро показывают, выпускал ли кандидат релизы или только коммитил в ветку.
Мы уже разбирали разницу между APK и AAB. Здесь пойдём глубже: как устроен App Bundle внутри, что такое feature-модули, как работает доставка по требованию (on-demand) с Play Feature Delivery и какие ограничения нужно держать в голове.
App Bundle: формат публикации
Android App Bundle (AAB) — это формат публикации, который включает весь скомпилированный код и ресурсы приложения, но откладывает генерацию и подписание APK на сторону Google Play. Вы загружаете один файл, а Play собирает из него оптимизированные APK под каждую конфигурацию устройства: только нужная архитектура процессора, только нужная плотность экрана, только нужный язык. Подробности — в обзоре App Bundle.
Именно поэтому публикация через AAB стала обязательной: с августа 2021 года новые приложения в Google Play должны публиковаться этим форматом, а с июня 2023 года это требование распространилось и на TV-приложения.
Зачем Play это делает
Пользователь скачивает только то, что реально нужно его устройству, — меньше трафик, быстрее установка, выше конверсия. Разработчику больше не нужно собирать, подписывать и поддерживать десятки APK под разные устройства — всё делает Google Play.
Плюс у AAB есть две «надстройки» доставки: Play Feature Delivery (модули функций) и Play Asset Delivery (большие игровые ассеты). Новые приложения крупнее 200 МБ могут публиковаться именно через них.
Важно помнить и про ограничения формата:
- Суммарный размер сжатых APK при установке (базовый APK + конфигурационные APK) — не более 4 ГБ. Повторные загрузки on-demand модулей должны укладываться в тот же лимит.
- Формат AAB не поддерживает файлы расширений
.obb— их место заняли Play Asset Delivery и feature-модули. - Для частичного «сайдлоада» APK без Play (когда установлены не все split-APK) возможны сбои — Play гарантирует, что при установке через магазин ставятся все нужные компоненты.
Dynamic Feature Module: что это
Dynamic Feature Module — это отдельный модуль (подпроект Gradle), который содержит код и ресурсы какой-то функции приложения и не входит в базовый модуль. Его можно доставлять по условию или скачивать в рантайме.
Типичный пример из документации Play Feature Delivery: маркетплейс, где модуль «Продажа товара» с камерой и описанием нужен только 20% пользователей. Выносим его в feature-модуль — и большинство пользователей не качают этот код при установке вовсе.
Технически это отдельный Gradle-модуль с плагином com.android.dynamic-feature, который объявлен в базовом модуле:
app/build.gradle.kts
plugins {
id("com.android.application")
}
android {
namespace = "com.example.myapp"
// Модули, которые расширяют базовый
dynamicFeatures += listOf(":feature_payment")
}feature_payment/build.gradle.kts
plugins {
id("com.android.dynamic-feature")
}
android {
namespace = "com.example.myapp.feature.payment"
}
dependencies {
// feature-модуль всегда зависит от базового
implementation(project(":app"))
}В feature-модуле не нужно дублировать то, что он наследует от базового: версию приложения (versionCode, versionName), конфигурации подписи, minifyEnabled. Всё это задаётся в базовом модуле. Если продублировать — получите конфликты сборки, о которых документация прямо предупреждает.
Способы доставки feature-модулей делятся на четыре типа:
- Install-time — модуль ставится вместе с приложением (поведение по умолчанию). Может быть помечен как removable — тогда после выполнения функции его можно удалить с устройства.
- Conditional — модуль попадает в установку только при выполнении условий: определённое устройство, локаль, минимальная версия API.
- On-demand — модуль не ставится при установке, а скачивается по запросу в рантайме.
- Instant — для Google Play Instant: пользователь «пробует» функцию без установки приложения.
On-demand доставка и Play Feature Delivery
Самый интересный для собеседования вариант — on-demand. Скачивание происходит через библиотеку Play Feature Delivery (раньше — Play Core). Классическая схема выглядит так:
- Создаём
SplitInstallManagerчерез фабрику. - Строим запрос
SplitInstallRequestи указываем модуль по имени (то же, что в манифесте какsplit). - Запускаем установку
startInstall(request)и следим за состоянием через listener.
PaymentFeature.kt
class PaymentFeature(private val context: Context) {
private val manager = SplitInstallManagerFactory.create(context)
fun downloadModule(onSuccess: () -> Unit) {
val request = SplitInstallRequest.newBuilder()
.addModule("payment")
.build()
val listener = SplitInstallStateUpdatedListener { state ->
if (state.status() == SplitInstallSessionStatus.INSTALLED) {
onSuccess()
manager.unregisterListener(listener)
}
}
manager.registerListener(listener)
manager.startInstall(request)
}
}Есть и вспомогательные операции: deferredInstall (скачать, когда приложение уйдёт в фон), installedModules (какие модули уже установлены), deferredUninstall (удалить неиспользуемый модуль).
Что важно знать про on-demand
Скачивание модуля по требованию поддерживается на устройствах с Android 5.0 (API 21) и выше. Для старых версий модуль нужно «вплавлять» в базовый — это называется fusing. И ещё одно правило: без SplitCompat приложение не получит доступ к коду и ресурсам скачанного модуля — его подключают в Application.attachBaseContext().
MyApplication.kt
class MyApplication : Application() {
override fun attachBaseContext(base: Context) {
super.attachBaseContext(base)
SplitCompat.install(this)
}
}Сценарий, который стоит рассказать на собеседовании: пользователь впервые заходит в раздел «Оплата» → приложение проверяет, установлен ли модуль (manager.installedModules), если нет — показывает диалог и запрашивает загрузку → после статуса INSTALLED запускает Activity из модуля. Если скачивание упало (нет сети, нет места) — модуль просто недоступен, и приложение должно это пережить без краша.
Ограничения и подводные камни
Feature-модули дают гибкость, но за неё приходится платить дисциплиной. Вот ограничения, которые я спрашиваю на собеседованиях, — и о которых почти никто не знает:
- Не увлекайтесь количеством модулей. Установка 50 и более feature-модулей на одно устройство может привести к проблемам с производительностью. А если настроить больше 10 removable-модулей на install-time доставку — вырастет время установки.
- Не экспортируйте компоненты из модулей. У Activity в feature-модуле не должно быть
android:exported="true": другое приложение может попробовать запустить её до того, как модуль скачан, — и получить краш. Проверяйте, что модуль установлен, прежде чем обращаться к его коду и ресурсам. - Код между модулями не вызывается напрямую. Класс из одного модуля нельзя статически использовать в другом. Правильный паттерн — интерфейс в базовом модуле, реализация в feature-модуле, а доступ через отражение.
- Тестирование on-demand. Чтобы проверить сценарий без Play, используйте
bundletool --local-testingиFakeSplitInstallManager— он эмулирует запросы/скачивания в локальных тестах.
Самое частое — забывают SplitCompat. Модуль «скачался», статус INSTALLED, а приложение всё равно падает при обращении к классу из модуля: SplitCompat не подключён, и классы просто не видны. На собеседовании эта деталь мгновенно отделяет тех, кто реально работал с feature-модулями, от тех, кто только читал.
Вопросы на собеседовании
Соберу, что реально спрашивают и как отвечать.
- AAB — формат публикации: Play генерирует и подписывает оптимизированные APK под каждое устройство; с августа 2021 обязателен для новых приложений.
- Feature-модуль — подпроект с плагином
com.android.dynamic-feature, объявленный в базовом модуле черезdynamicFeatures. - Доставка — install-time, conditional, on-demand, instant; on-demand требует Android 5.0+ и SplitCompat.
- Play Feature Delivery —
SplitInstallManager,SplitInstallRequest,startInstall(), listener со статусами. - Ограничения — 4 ГБ сжатого размера, до 10 removable-модулей, без
.obb, безandroid:exported="true"в feature-модулях.
И типичный промах, который я слышу постоянно:
«App Bundle нужен, чтобы приложение занимало меньше места на диске у разработчика». Нет. AAB — это формат публикации; на диске у пользователя всё равно лежат собранные Play APK. Меньше становится то, что пользователь скачивает при установке, — за счёт того, что Play отдаёт только нужные под устройство split-APK.
Если спросят «зачем вообще нужен feature-модуль, если можно модуляризировать Gradle-проект обычными модулями» — отвечайте через доставку: обычные модули компилируются в один APK, а feature-модуль даёт независимую доставку и экономию размера установки.
Меня зовут Рустем Бикбулатов, я senior Android-разработчик и ментор Яндекс Практикума, провожу технические собеседования. За время менторства у меня больше 100 учеников и разборов. Сборка, Gradle и доставка — стабильно входят в список «слабых мест», которые мешают кандидатам с опытом 1–2 года перейти на уровень middle.
Хотите закрыть пробелы в сборке и публикации?
App Bundle, Dynamic Feature и релизный цикл — это не «скучная тема для DevOps», а вопросы, которые отделяют middle от junior. Бесплатная диагностика: разберу ваши пробелы и составлю план роста за 30–40 минут, без обязательств.
Итоги
App Bundle и Dynamic Feature — это про доставку, а не про сборку. Вы публикуете один AAB, Google Play собирает оптимизированные APK под каждое устройство, а feature-модули позволяют не включать часть кода в установку вовсе.
- AAB — формат публикации, из которого Play генерирует и подписывает APK под конфигурацию устройства.
- Feature-модуль — подпроект с
com.android.dynamic-feature, объявленный в базовом модуле; доставка бывает install-time, conditional, on-demand и instant. - On-demand —
SplitInstallManager+SplitInstallRequest, требует Android 5.0+ и SplitCompat для доступа к коду модуля.
Что запомнить
Одна фраза для собеседования: «App Bundle откладывает генерацию APK на Google Play, а feature-модули позволяют доставлять часть кода по требованию через Play Feature Delivery — с проверкой установки модуля перед обращением к нему». Добавьте пример с SplitInstallManager и упоминание SplitCompat — и вопрос закрыт.
Если вы писали код, но релизы всегда выпускал кто-то другой, — самое время закрыть этот пробел: на собеседовании он «стоит» заметно больше, чем кажется. Напишите в Telegram, разберём вашу ситуацию и составим план подготовки.