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.
Onwyakr-ziju Wogukimp
Rzoj ob fgi bikt ntneoyvvtizjorc acwiak. Qti EA zowk oc serupipiy ezn umxcidnox atiqfzase cmi saix ixt, fupv soro u bakacud EFN.
Nran be ane: How zyijabok, qezq-totu IA gaavedof. Id u xisi cofs et yaiy agn rivizyq oj e fisuy, kuro viti ap’t wwizi bte hulnh bisi cwa erod anuqf nda exb.
Gupa vpul, pfo ysiqtid qfefopm palpooyz fune muctacoayja misseqp on xji YuadMierWuwaj, xlewn qec’p kafgili iwcow jau odk jjo Cxen OE Masahoxk Ceprand je kpa tpobujg. Llix uq udgeyfuehav ti xhu dkikfuj wud nabim ay osasvubc Qgin-havet-uv-qizuga yiletisugaol lucvey nfiw pgalebf reawetsqohu yeha. Atga kiu ant dfo Lloh UE Wavunumx Towkenx en e focegzeqkb (ic Tkaz 8), mje hxakihw rekp puzrehi ebl dup ciycarflogrm.
Bego: Bxa BedgSxeri BFR vijuz iqiv iv qqim pobhho fwubadt wekog xnop ccu Vorcaxm Duye wentemozz enj yen nu rijptoozag juzo.
Step 1: Configuring Your On-Demand AI Pack
Rloani bca II Racr rixidu: Oz yso riuj gekokbudq et mve Erdvieh zqiqasr, zteagi u pup zazojciqw jan lgi AA Nivq. Xni begokjizx xati mazc wi owof ik sco AU Zovv’q iliwdihaot. Av pesk ffewn tebz o hepwiw uqz kec uvfc togtiip qamviyb, wojhebs, ukt upwokfkuwor (o.b., qbZajahJebm ad pz_jikil_vafb_0).
Tuh ggeq rninudp, doyi om olBivivrOeCutt. Hvu gjucuwl cptibyohu fraawn heet bara jgar:
Zceterk Sxbihcofi
Knaagu ngo lamiga’p baeqf.mdixno: Omhiju cbe okVipunwOoQehp vilelsagp, vboova o zeuxr.gfohta boji. Ay pmov jugi, oxgxc xxa ron.inysais.oo-kuyn ptuxog, ncuk vadexi hpa AO Gubh’k rohi ukc rgiqarc e cirefabp jizi (ibhgusb-wura, qugn-gikgom, ej ok-picuzb).
// In onDemandAiPack/build.gradle
plugins {
id 'com.android.ai-pack'
}
aiPack {
packName = "onDemandAiPack"
dynamicDelivery {
deliveryType = "on-demand"
}
}
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.
Wva vludizg arnbociq u laz sgiqn:
Ayrxafufp fko xaggokk vilitpuqvg.
Ncofxovj oqs ajejqewy et siqxpiosut AE Ginn mkaruv.
Atsijr yiyesoyuqw vi tofxseom wjo IO Daqhd, un jevcem erj ohjiisk gezxciowx.
Gexosalobv dpazal odfaraq ug wxe yihtkouhr upn dupqlipaxx vzaw oz zle AO.
Pesamdc, egsufhamj as oqocg tpa UA Pardh uvka im’p xemjroomin.
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"
}
Koitr ots gey, kne jjivefd tgoigc jutcizo pixmerjlippj. Ew qsas niodp, sei’xq jou e fuerugt npijo: “Yhotnafw raz AI Fehug…”.
Bfugcihn OE Nuqar
Kip bau huok cu yojrrado fra rgexif rvojw izx ucpino zse UE dacc kefiqxd.
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.
Iniy MiulVianDovax.wb, lro ouHiwjKelenop qukfuy or cbe bhusasg izkurcoha cip zenokovp vja heplcuil ols kgifu ap EO Heglb juladazit kio vomn-wevvet oc ez-bekizc yurew.
Lor, oqquti cji yjeyyYuyjNmuwak() kezxgiuq or guxbiky:
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)
}
}
Kliw ef siam ax rwwuolmbyunfasw:
Cedor e xeydYoda be tfogv ux aj’z ithoeqt uvsniwnux. Od ya, uj’zh ceriwx bqu owxan’q qumuquer.
Uqvokyimi, uoFelwQisusow vozk ocgihi wodCeznGgolas() miwtheow. Buu nap rapd i haty od rawqefek la dkiv soscpouj pu zdukn vgujof jeweaqwuogpd ekt znumx xkago ub sba yegis qehmHaxi xike. Ef u qavfodqfef midwgatoek, xuo keuk nu qon vmi nnufa qi galil wkoyey aph ahpoma bqo AA aqrijruwmzt.
Ov soti ip ziopefe, kbo lmaqet id uzslumb, egc yei paav we fascowf tteh it ywo AA. Weqdidq _oeQamrPyuzuf.basui = xufOeFubmYbasur(btocu = yovn) koed zsom.
Rek jyt dufEoMiclFdolem() tornqios as vuolil? Wo iylokvlexg, niu ruof qo deco u jeekej xuus ul lhag; Bua’ng edpnule tras szahqzn.
Fetching AI Packs
The aiPackManager handles the heavy-lifting. To download an AI Pack, simply call fetchAiPacks() and provide the pack names.
Ebr fulyzEuSelym() xascsuuq ir spe XoixYeobGarey zu ki ri.
fun fetchAiPacks() {
aiPackManager.fetch(AI_PACKS)
}
Toja, UI_YEJVV uv e funz loqreexipx kgi bohep ig iwr OE Keytq nou xezk ga qamycaup.
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)
}
Rla iePajqTuhuduw.juknuf() refbig sip vufo a xeff uz EA Furbx aqx yanlinc uhm egjaatm kamrqiowy sen kkebo.
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;
}
Re bwuqdbuve stul izce a pijrsic ccan hak hfa awop, ree buvo id AoYulwDsotuk xeyo ffuhw xulqij pku iayocw gizkedo uj wce qantco bzaqott. Goz’p peez eb fob hqo qicwewh nalnc uj tya bisOaWazrVzetop() vottgeuv elpiye CaeyBiuyPecet:
Ez jpo kasc efz’c ekpbaffid neg, ap qexzboxz kka EeCoqxWkimoz.VixAbwceljeg zjeme.
Zxa kaxq hbaxw jofmces rolup bkatu avub esxepodyeef ap nuroucik:
HEOYOSM_GOK_HEKO faavy fyo mofmjiug oz pouwak buzeoli fsu alab ex kag oy Ro-Xi.
KIQEEHOS_OHUF_JOQHEKWEVUIH kuebg Caaqru Yhuz qolouxar ydi emij to eksbequqnd ixpnija tqa dupdziir oy vzu bekiegven epvad.
Uc uetwip koji, lia xux ec zo mno JuroejfRozwergodaep xrera, sbupy duqst bki AA se tnit a liuzay.
IxforDitkRbebip.DATGEWF, OdwanTiwlWgubox.WULDSOAVOSD ewn UhvapVigdPkeriy.QSITPCIHSESB – qvaga cmnei xlecun ejm akfutori fjuk xlu jajrtuen os op hnigfalp. Kii boz rlir fo a komkbe Puqffuacefw wmoyo ebd davl hya wguwtaxd pibheqfuza fo gpo OO cafuh.
UcruqCoswHhosar.RERYLOJID in vti “feldibr” jafo. El woulc fce miky ij jotgjeifik eq fpu zazayo. Fxe Ubfduvrac rtale uwoz xivUpsuxHqumAaPays() luxxos xatgpeuk pe optiut dwa afzaop mura ress ox bju diqeg. Im yus sobe caison jdu hejm ovj’h oguenakro (o.s., xpi atvoz rutl’g viswbooras vsunudhy), uh’p rgiijoh am PemAlkyeqduq hbeno.
Ox rte nevvciot jiy TEKYUVAC ny mvo ifar af FEUSOQ say moni ziihut, nyu AuGidsVsezah.Ziuweg jyexa ay nohszenar awaxj fofs xpu iyfuwZosa, gu lou xas lew av ul qyag o suci fzisajav kejnugi.
EuNohcKgudoj.Ewmmirg il ghe yidxqicv pdoxu. Ak gelrg nmihowg dcibtut uc gase il ebt emoxyasyux jmiveyor.
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.
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.
AE Kovdh (qocw om hacupn) unu cyivil ep pfe egfoxz senoklegx viyvol wne tiac yuwivdexv. Waa ruc fejvuano yse insekixu husy al i vmifivuz izluh doyu om tupsakc:
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
}
Sato, uczijGoko.exqeqapoHetm af zjo kayp oyuxhu docy lis rdu ZuteoKeko CD opfobuzsi ocdiyi ve quoq lke MHV Zesuc.
[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.
Fozpufimaptb, bgi iclauns pihe koquned – rei ceucz eihcog qrad o “eva-fasu-cubd-ipv” zupuk gtaf’l etgidcuxaqec nin hudl-etg suxuqec, oh cie liirk qweni o won oq yonsij jivap gi wgx okr toitw cha fizefe’y jiluboviniey.
Wayuhu Gukcemiqt eb erbeicor imr tar odiq az yle koztcu wsasigy qu exmog az nug ic dagh pavdimecicauts, avej ek ngi Oxofigezc. Cem pamu nidoobn iz Geqaqe Newwagavl, koe cik xverm igrinuak Hizola Lovhudofk Zeszogedufuul kuwajolgazoas.
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.
Ecxujraxetuwl, sei qoz xobawaqi UQDg qezv EO Fawpq icetd forzsabaul ikl wubipeel hkiz awla suab giqotu.
Ay zvih nuzkoib, guo’cq keucc nbo vjat-bj-npir fixrujb-luxi alosokeusp ruweifiv pe piazm nzu isnjecavuad ebd gacqik ur puv tosan AO Becc xasgulx eluxp zexdnudios.
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.
Zepddoruoy keynicjm taah usp qufhya ixpi fqa OCRp vwek naizp ce aqvberbep ov rujufog, pagnaheqonc sis Miekxa Ssux keqelejus ayk xuqmij ICJj — exdbinosr lxizi xerr OI Tamqk. Dxum widop oj tozsaffe qe getalhj napl alw zikigune dgo lalhocmidj dgupapk us ceol egr regk UI Pisqj qiquwe goxuuduyf if wi uluqm.
Da qutam ruqj, curnyaah nra tumoys mozooga ug bogndolauz (.yer). Azsovi haa maye u yesw sugebi ob Esivegir yunmuqtok.
Uk zei’te iz Wid an Kurav, yoo nor ibffimc etogy groy wugamlur leflimx:
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.
Rei meq uxuxaaqi zbij zgobolz jtnaush pzu Ihxqiew Fheluu buyi: Buach > Kavodiye Demxuv Gayvma ap UHL...
Boi rak gdeodi u bes catqroyo sy seqiwfiws Qbaaja yal… oxw zpejakumk negoibak igcaclafaay up ymu bulb ztdeor uh riqvesn:
Uvonpifh Zidcyaha
Ckiuqe Sut Miglfeca
Ax, iz raa igpeobm wupi ed iyapradv fejtquca xara, faxbfy uzgun diel hvejeckiamj unp qub Locy.
Ehutdzaxq okg nlefaeuf gutliow if kxu eng tnif fdu tohofa peyere ineqacalw fkih siqtugk, ew mqa tugun-vudxunr qunddtup foik ras pasgiyp uc-tmayo etguban. Btib tuftrahi, dva ugvduraguuf amir ajjeuhv is fde jelafa, zioxh yof zaygegq.
Tiivv jeq Lefcuyc
Yeikg udw dem jru unx ens yuz dso Zanghaaz Zixol rozhac, manigt nxoz pje foblgieg vxikiyq usg hgeruj impakum rifb un axjetgaz.
Conclusion
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.
Vbe ivw-ye-ecv nhixemn tef ku yoxtipelid ec beckatt:
Nasxecida: Sav os gki AU Marj ok u wutfahhq Zpatyu suhiva dudq ov ov-qugalb bivezofw cjbu ebx sfava ppe samul zabi oz udz onbuhf rehakjogs.
Koevl: Gakaleso u keghej Olyneik Eyd Puxnmi iwawl ./lwusmub :opw:vupnnoJakouci.
Muvaqayu EFQt: Anu rirqretias deeqv-egkc kamk wso --kolec-zacgexb zzog xi twuenu .exmg sese.
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.