Connect with us

Разработка

Доставляем 584 Мб модель Gemma через Google Play

Он позволяет не включать 584-мегабайтную модель непосредственно в APK: Google Play сам хранит и доставляет её пользователю, поэтому разработчику не нужно организовывать отдельный хостинг и загрузку.

Опубликовано

/

     
     

Я работал над своим Kotlin Multiplatform-приложением для учёта коллекции покемонов — PokeCollect — и добавил функцию, которая использует локальные LLM на устройстве, чтобы отвечать на вопросы о моей коллекции.

В качестве модели я использовал Gemma 3 с 1 млрд параметров размером около 584 МБ. Через LiteRT-LM модель работала нормально: ей можно было задавать вопросы и получать ответы в структурированном формате, который мы заранее задавали.

Настоящей проблемой оказался размер модели. Gemma 3 — довольно способная модель, но она занимает больше половины гигабайта. Если положить её прямо в приложение, размер AAB/APK заметно вырастет. Пользователь может просто не захотеть устанавливать приложение размером 600 МБ. Именно здесь пригодится Play for On-Device AI. Он позволяет не включать 584-мегабайтную модель непосредственно в APK: Google Play сам хранит и доставляет её пользователю, поэтому разработчику не нужно организовывать отдельный хостинг и загрузку.

Это новая библиотека Google, пока находящаяся в бета-версии, которая позволяет приложениям загружать ИИ-модели во время установки, сразу после неё или по запросу. Она построена поверх Play Asset Delivery, где ресурсы загружаются только тогда, когда действительно нужны. Например, приложение с обоями может поставлять маленькие превью, а полноразмерные изображения скачивать только тогда, когда пользователь открывает нужную категорию или хочет установить конкретные обои.

Как использовать библиотеку

Шаг 1. Проверьте инструменты

AI Pack работает только внутри AAB, поэтому если вы распространяете приложение в виде APK, воспользоваться им не получится.

Также нужны AGP 8.8 или новее, bundletool 1.18 или новее для тестирования на устройстве.

Шаг 2. Выберите способ доставки

Библиотека предлагает три варианта:

a. fast-follow — модель загружается сразу после установки приложения, даже если пользователь его ещё не запускал.

b. install-time — модель скачивается вместе с приложением при установке из Play Store.

c. on-demand — модель загружается только тогда, когда приложение само её запросит.

Шаг 3. Создайте модуль AI pack

Это отдельный модуль, содержащий только модель и никакого кода.

gemma_pack/
├── build.gradle.kts
└── src/main/assets/gemma3-1b-it-int4.litertlm

// gemma_pack/build.gradle.kts
plugins {
    id("com.android.ai-pack")
}

aiPack {
    packName = "gemma_pack"
    dynamicDelivery {
        deliveryType = "fast-follow"
    }
}

Сам файл модели лучше не хранить в git: он большой, а Gemma ещё и gated-модель — для скачивания нужно принять лицензию на Hugging Face. В PokeCollect модель подключается небольшим скриптом, а соответствующая папка добавлена в .gitignore.

Шаг 4. Подключите pack к приложению и добавьте зависимости

// settings.gradle.kts
include(":gemma_pack")

// app/build.gradle.kts, inside android { }
assetPacks += ":gemma_pack"

// app/build.gradle.kts, inside dependencies { }
implementation("com.google.android.play:ai-delivery:0.2.0-beta01") //or the latest version

Шаг 5. Запросите модель и используйте её

После завершения загрузки можно получить путь к модели и запустить её. Если модель ещё не скачана в момент запроса, можно попросить менеджер начать или продолжить загрузку.

val manager = AiPackManagerFactory.getInstance(context)

fun modelFile(): File? =
    manager.getPackLocation("gemma_pack")?.assetsPath()
        ?.let { File(it, "gemma3-1b-it-int4.litertlm") }

if (modelFile() == null) {
    manager.registerListener(listener)
    manager.fetch(listOf("gemma_pack"))   // starts or resumes the download
}

// ready to use!
val engine = Engine(EngineConfig(modelPath = modelFile()!!.absolutePath, /* … */))

Шаг 6. Отслеживайте состояние загрузки

В зависимости от выбранного режима пользователь может открыть приложение раньше, чем модель успеет загрузиться. Библиотека позволяет следить за состоянием скачивания.

val listener = AiPackStateUpdateListener { state ->
    when (state.status()) {
        AiPackStatus.PENDING,
        AiPackStatus.DOWNLOADING      -> showProgress(state.bytesDownloaded(), state.totalBytesToDownload())
        AiPackStatus.TRANSFERRING     -> showProgress(done = true)          // unpacking
        AiPackStatus.COMPLETED        -> loadModel(modelFile()!!)
        AiPackStatus.WAITING_FOR_WIFI -> showUseMobileDataButton()          // over 200 MB on mobile data
        AiPackStatus.FAILED           -> showRetry(state.errorCode())
    }
}

В зависимости от состояния можно показывать прогресс в интерфейсе или через уведомление.

Тестирование

Механизм загрузки можно проверить и локально. В local testing режим fast-follow ведёт себя как on-demand, поэтому именно вызов fetch() запускает загрузку.

bundletool build-apks --bundle=app-release.aab --output=local.apks --local-testing --connected-device
bundletool install-apks --apks=local.apks

Важные замечания

1. Разрешение Internet не требуется. Почти у всех приложений оно сейчас есть, но если вы хотите подчеркнуть полностью офлайн-сценарий, это хороший плюс. При этом библиотека добавляет foreground service для загрузки. Play Console попросит задекларировать его и приложить короткое видео.

2. Ограничение размера: до 1,5 ГБ на один AI pack.

3. Опционально: device targeting. Можно отправлять разные модели разным устройствам, например в зависимости от объёма RAM или чипа: более мощным смартфонам — более качественные модели. Но это требует нормального тестирования.

Вот и всё. Теперь можно выпускать приложения с локальными ИИ-моделями, которые после загрузки работают полностью офлайн, не раздувая основной APK на сотни мегабайт.

Пример кода: PokeCollect на GitHub

Если вы нашли опечатку - выделите ее и нажмите Ctrl + Enter! Для связи с нами вы можете использовать info@apptractor.ru.
Telegram

Популярное

Сообщить об опечатке

Текст, который будет отправлен нашим редакторам: