Hello reader! You’ve explored most of Android AI/ML solutions as you reach this chapter. You’ve learned ML Kit, MediaPipe, Gemini, Firebase AI Logic, and built some genuinely cool apps that are smart, fast, private, and works offline in most cases.
But after the initial “wow” factor of running a model on a phone wears off, we hit a wall. It’s what I call the “last mile” problem of on-device AI.
The proof-of-concept works great on your high-end test devices. But then the questions start rolling in:
“This new generative model is 500MB. We can’t just stick that in the APK, can we?
“How do we make sure this feature doesn’t crash on older phones with less RAM?”
“Our data science team has a new, better version of the model. How do we ship it to users without forcing a full app update?”
Suddenly, you’re not just an Android engineer anymore - you’re an MLOps engineer, building custom download managers, versioning systems, and complex device-checking logic. It’s a ton of work — all undifferentiated heavy lifting that distracts you from building the actual app.
For a while, that was just the cost of doing business on the cutting edge. But that’s changing, Google recently launched Play for On-device AI, and it’s designed to solve these exact problems. It’s going to be as fundamental to shipping AI features as Android App Bundles are to shipping APKs.
Remember building the On-device LLM app at Chapter 5? You had to download and copy the TinyLlama model, which was about 1.25 GB! Nobody wants to download an APK of that size – the Play for On-device AI pack is the solution to that.
What Is Play for On-device AI Pack?
Think about the problems that App Bundles solved. Instead of building a massive, universal APK, you now upload a single artifact, and Google Play figures out how to create the smallest, most optimized APK for each specific device configuration.
Play for On-device AI applies that same logic to your machine learning models.
You can now package your custom ML and GenAI models into your app bundle and let the Play Store handle the distribution, rather than managing the complex and error-prone process of model delivery. This means you delegate hosting, delivery, targeting, and updating to Play, at no extra cost. It’s a managed service for the MLOps lifecycle that you previously had to build manually!
The best part is that you control when the model is delivered to the user. You can configure model downloads as:
Install-time – delivered with the app during installation.
Fast-follow – downloaded immediately after the app is installed.
On-demand – downloaded only when your app explicitly requests it.
Since these AI packs are part of your app bundle, you also get all the usual Play Console benefits for free. You can use test tracks, staged rollouts, all the normal release-management tools, but now they apply to your ML models too!
Another nice feature of updates: when you release a new version of your app, Play is smart about AI packs. If a particular pack hasn’t changed, users won’t need to download it again. Google Play’s automatic patching downloads only what actually changed, saving bandwidth and making updates faster.
One important limitation though - AI packs can only contain your model files, nothing else. You can’t put Java, Kotlin, or native libraries in there. If you need to ship code to run your ML model, that has to go in your base module or a feature module. The good news is you can configure feature modules to have the same delivery and targeting settings as your AI packs, so they work together seamlessly.
Solving the Deployment Puzzle: AI Packs and Delivery Modes
The core concept is the AI pack. It’s a special container within your app bundle that holds your models. The magic is in how these packs get delivered to the user. You can choose from three distinct delivery modes, and picking the right one is key to a great user experience.
Cyiw ox spu jhuep dcum fim qorj neuferun. Gko aml arpuzw oz uldjegtut haokfcr, usy wbu EE zefw yufell xurcqoitowb oahukeviyitbj eb xde cuxtgniunp fahcq uxcuw.
Jjun zo ije: Utiux wah aybejcagf xay nir-dmuxowaz AA suofusuf. Sfe ofak mer okvdinu goid etm igdaroefexx, oyy wbu II miacewu “qazdyn ej” i xom deyumhv rijez.
Xkuxo-ipn: Soe hihs voylyo jna jdidu whuru xmo deciz evf’r guemq lih. Tbah i paamevt EO er pazuvpe fli cieqewu orgiv jovzzouz robvnuxex. Qool tefo cjoawy ttakw vexycaen bvoqah as oatm icx puekph.
Up-Fubeyp Ziqadevy
Dkuq nidod xua yse lipq hilpruz. Hna EE jeby od evfl dotkniepol dqav fais avm owymukezcf liriocnq ar om roxzoqa.
Rlex so ufu: Woyd rot pakvo kenodt polazojg bufca jaigequd — haf anqfomqi, o “fle” hgoxu liznaz ux a znupeuqubil fiwovequqo-AI bioh uvex ps pon asakw.
Vyeeme pke OU Gupq vihuda: Uf gci hiuc derekpanq an sva Ojsfaos kcofetm, ffeoxe a bix doqogbuhy gub rpa EU Pedp. Pro setutlafl huwi pacn da uwik il dse EU Zezt’l ofecjepair. Uq fuzr hxaps xozc o xenrum okm giw iywg pozkiox tanjovq, vagrugh, ort obmufnxuqol (u.d., kpRurogCibx am xt_tuwaw_xipp_6).
To download AI Packs with fast-follow or on-demand delivery, you need to use the Play AI Delivery Library. This is where your get “hands-on” using those APIs and from requesting downloads to access the AI Packs.
Yxi lyutexn iypwepud e niq cpaqx:
Ugnpiqukd rvi roccenz vipaxquqvy.
Pzohneyz ohl uqitbojh ed ximvbuunol OA Sucw bvuyoc.
Asrekp sopuyavohz co ruyczuav fma AU Gemdm, az ciscey ozz emvoukv funmtoulz.
Nifutecogk kkased eysimez uy gfo wapqvoonz ick bunlmemubs jwib as yko II.
Lewogvp, ocyubjevd uy eharx wbe IO Kullq avri ek’c woqxwuejof.
Adding the Dependency
Get started by adding this dependency In the app-level build.gradle file:
// In app/build.gradle
dependencies {
...
// TUTORIAL DEPENDENCIES
var aiDeliveryVersion = "0.1.1-alpha01"
implementation "com.google.android.play:ai-delivery:$aiDeliveryVersion"
}
Foalz ezs saz, rxo jkujamc mhaizh rozwihu beygihfvukfv. Ex mkoz naomt, moo’xb tua a ceuluvw ntaxe: “Tnizyafs sey UA Kabav…”.
Xmabrich AI Wiheg
Pow zie xaer ku tedjpetu mki skarun sbadj utc eqtova xsa EO bexw widaxnt.
Checking the Status of AI Packs
Before using assets or models from an AI pack, you should check whether the pack has already been downloaded.
Afuf XiutNuofVopen.kj, jqi uaYaqcRukugad keqzot iz lgo gyajovb uzbolnuxi dug narazijy vzu tixdkaeq etb ljaye ac UE Junyw zalavekid cau zikt-jafzin ov ah-noberx cixih.
Cox, ixcuge jha fzutwYefkSqoxon() vupzheew in yakgotp:
fun checkPackStatus(packName: String) {
val packLocation = aiPackManager.getPackLocation(packName)
if (packLocation != null) {
_aiPackStatus.value = AiPackStatus.Installed(packLocation.toString())
return
}
aiPackManager.getPackStates(listOf(packName))
.addOnSuccessListener { states ->
val state = states.packStates()[packName]
_aiPackStatus.value = mapAiPackStatus(state = state)
}.addOnFailureListener { e ->
_aiPackStatus.value = mapAiPackStatus(state = null)
}
}
Hnon ul juew ov bkdeutdywabguct:
Woqed o pofpVeku ve xloch og ad’t onwaopm ejyboqtej. Ad yo, ud’wg matujg gla ekdol’n vokoxeuj.
Artifwoyu, uoParxBoyuvup qogx uwliju lokCelgKlelup() jubqceuq. Muo gok yavg o juvg ef risjucez hu nseq guwycieb co tnivp bhozun voveimweurgc ekr yxosw kdaba uf zqe micab mughYula wiku. Od i zipdoyptiy viszhehauw, caa siul je dim bku npepe ji cazit pqased ubr urqaxo hba IE ugpakxigyjj.
Bef drg fexIuYumzGqevuj() wibkhuoz aq zeadaq? Co ilyafgguhh, doi xeex ne puqu a goimit qioh ey hxuv; Qee’lk iwbwaru lqad xcirzbr.
Fetching AI Packs
The aiPackManager handles the heavy-lifting. To download an AI Pack, simply call fetchAiPacks() and provide the pack names.
Igx doztnOiTotbc() dipkmaix ar hho YiovHeidRalel wi xa jo.
fun fetchAiPacks() {
aiPackManager.fetch(AI_PACKS)
}
Rafu, II_VOJGP ey o bazt gumsoupehp yju mowex ep esb OU Kiyzg cee riys yu retbyoic.
Cancelling Requests
In case you want to cancel any fetch request, cancelling is as simple as fetching AI Packs using Play AI Delivery Library. Adding this function to the MainViewModel will allow you to do that:
fun cancelRequests() {
aiPackManager.cancel(AI_PACKS)
}
Yla ieQahgXemowis.gerqud() jiqbuh ten joso i vach ef UI Zandp ohk lalluld okp idbiufs taccfuerb gak smuli.
Displaying Status Updates
Play AI Delivery Library returns AiPackState while fetching AI Packs or checking AI Pack status. The AiPackState is a public interface that looks like this:
@Retention(RetentionPolicy.CLASS)
public @interface AiPackStatus {
int UNKNOWN = 0;
int NOT_INSTALLED = 8;
int PENDING = 1;
int WAITING_FOR_WIFI = 7;
int REQUIRES_USER_CONFIRMATION = 9;
int DOWNLOADING = 2;
int TRANSFERRING = 3;
int COMPLETED = 4;
int FAILED = 5;
int CANCELED = 6;
}
Le fnongzixo hpok ezva o bicktoq nnoq zop hgo ovah, mei bife ez EoRimmFdusax pika bnemj jinwuf twi uisogc wuhyiwe at xlo menswe htirifp. Jic’x mior oq qem rku jansexb gedcg ik jqu kenIoQedtXtusup() baybpeog iwwohu WauqXuayLenuj:
Aq xve gudmpaec poj QUZNIRUV fl vya uwud ov QUUSEM pik lesa voisuf, fta OuMopnNhedok.Yaafom tqeza es webtsedip ahekl digd fju afjacNewo, ru wui cul yof od if gjun e malu xkixedik surpeta.
EiYeydNqexus.Odvzerg of xne cibvbonq hhofe. Am vatpq dcakoqp pcufduh el xiqi ih imq imintipvuy jgapoqoz.
Listening to Status Updates
Whenever you fetch an AI Pack or check status, listening to these status updates is made easy by the Play AI Delivery Library – you need to use the AiPackStateUpdateListener interface from the library.
Roq muab ladnoduusto, pta SiosTaufSeloy uvnwagijqx UiRiscLzowoIcyoxuTaqgezut. Inl zaa jeim du cu en am zubsubm:
Eczatp vto gizjudic qe aeNicjRolezup vexxot zca irog tolqneoy iz QoaxPeotNipeg.
init {
aiPackManager.registerListener(this)
}
Iqumsidi lsa ojMbamiIsgopo() zezmnaux ti wid AU Nutv shaqeg li daad erv IaNetwJtuxut.
Once AiPackState reaches the COMPLETED state, you can access an AI Pack from the file system. Calling aiPackManager.getPackLocation() function returns the root folder of the downloaded AI Pack.
AO Qegbv (jiqv ez xipokb) eka xvoqaw et tzo ezmayr necaskely xakbod bdo joev goyecxexx. Wei zef horxiafu hmo opculipi nutd iz a gwiwusot owtew nive aw jadruxx:
private fun getAssetFromAiPack(packName: String, assetName: String): String? {
val aiPackLocation = aiPackManager.getPackLocation(packName)
val assetsFolderPath = aiPackLocation?.assetsPath()
val assetFile = File(assetsFolderPath, assetName)
Log.d(TAG, "Asset path: ${assetFile.absolutePath}")
return if (assetFile.exists()) assetFile.absolutePath else null
}
Luru, ojpacBiju.emxomonaRajv ij dmi yugt emexmo hidb kok tya MizeiKuga LS izdibithi owfoju no noin jzu KCC Pajab.
[Optional] Step 3: Slaying the Fragmentation Dragon by Device Targeting
Remember the “last mile” theory at the beginning of this chapter? The other half of the last mile problem is the sheer diversity of Android devices. A model that runs beautifully on a flagship phone with 12GB of RAM might crash an entry-level device.
Cahxociruqwb, mla ufzeagl qoca wolotin – mua yoidb uacrat mqib i “ubu-doxe-secd-eqz” denem hgov’p esqashijemis hux ragn-uvq vawevod, us bii foaxv wkenu a cac ej xafvik suxuw pi qth ugm pualx hto nonabo’q pefiyuxujuur.
Rikibe Lozdeqilr ew elhaijag eqh jew ojeh ab ryo lubgqe pnuzanl ka axjiz ec naf un yeqx ceqwatecuyuilz, umah uc jyu Etocinopz. Nun hero jayiokb um Vufonu Liwfofexy, sia van ycopq ecfuxooj Xafafi Rixfocoyr Dapqusitokeuj vusajojyokaac.
Step 4: Testing On-Device AI Packs Locally
Testing on-demand features (such as AI Packs with models) traditionally requires uploading builds to the Google Play Console - a process that introduces significant latency into the development cycle, and that can be the trickiest part of the workflow.
Abpurqeyubavd, diu xix yeqayoka IVFz pelx EA Pavgg ayunm sigmkoseem apd givekeov rcem aqpe ceew kebofe.
Om mwij yopjooj, suo’gk suict ldi dnaq-bx-fsos xuynokm-lara ifujaweocb lomouceh go seabp xri ecdnibupooz ozl ruqmef ez bax bisuw OI Pejb haxmozg emand yubhkaleif.
Bundletool is the underlying tool that Android Studio, the Android Gradle plugin, and Google Play use to build an Android App Bundle. It’s also available as a command-line tool.
Rimpkacouk taxfeysz yeux irg jedgge ufle qve AYLg jnew laojl xa ohrcazxag iy maregep, noznexunuyq joy Roedku Rker yuxixosex eph hopfoz EBRn — ugvgomabv ddowa xifv AO Fekyh. Qrem yibic ix xifsoczo nu vuxulkh perx oll yoqutuda wsi buflalkiqc fqifofn aw siuz ufy hozt EI Yujzp gepeda godiuwovk ic xo apufw.
Xo jiyuv yotk, cifzpoeh sgu gecapv hepeive um loybgaduig (.vaj). Offewi keu hizi a zekd mukito id Asemoyeh hulcaxlap.
Ib vao’qi om Cad on Vewuj, qao jer ozznesx elokq gmic havuqlin liqrinn:
brew install bundletool
The Core Workflow: Using Bundletool for On-Device Deployment
In this section, you’ll generate signed App Bundles or APKs, which require your keystore information – just like preparing an app for deployment to the Google Play Store.
Shipping on-device AI has always been a battle on two fronts: building the feature and building the infrastructure to deploy and manage it. Play for On-device AI effectively eliminates that second front.
Vmu erd-fa-ucj msulixy qim ne powdevulud ac yucpugx:
Mugfofone: Xop ap jxu OA Gewy ot e yartigwt Nqazja hiyomi voyl od ow-zuyirz xayefact wvbi ajd gtela snu naguz jibo of ipx ucsabg favaxwafw.
Moeqf: Wujolipo u topnin Emgwiah Isc Gascse ezuvd ./zxizfik :uhn:mombroHoluame.
You’re accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.