App Size Optimization

A smaller download size means fewer users abandoning an install over a slow connection or limited storage. With a signed App Bundle ready, the next step for RecipeBox is making sure that bundle isn't carrying more weight than it needs to.

R8/ProGuard Recap

R8 already does the heaviest lifting: shrinking removes unused classes, methods, and fields, while obfuscation shortens what's left. Both run automatically on a release build once minifyEnabled true is set — that lesson covers the full configuration, including -keep rules to protect classes accessed via reflection (like Gson model classes for Recipe).

Resource Shrinking

minifyEnabled only touches compiled code. shrinkResources removes resources — layouts, drawables, strings — that R8's analysis determines nothing references anymore, such as a leftover recipe-card layout variant from an earlier redesign.

// app/build.gradle (Groovy DSL)
android {
    buildTypes {
        release {
            minifyEnabled true
            shrinkResources true
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
}
Requirement: shrinkResources true only has an effect when minifyEnabled true is also set — resource shrinking relies on R8's code analysis to know what's actually reachable.

Splitting by ABI, Density & Language

A single APK historically had to bundle native libraries for every CPU architecture and image assets for every screen density, even though one device only ever needs one of each. Publishing as an App Bundle removes the need to configure this manually — Google Play automatically generates a slimmer, per-device APK that includes only the matching ABI, density, and requested language.

Split dimensionExample valuesWho needs all of them?
ABI (CPU architecture)arm64-v8a, armeabi-v7a, x86_64No device runs more than one
Screen densitymdpi, hdpi, xhdpi, xxhdpi, xxxhdpiNo device needs every density's drawables
Languageen, hi, es, fr...Most users only need one or two locales
This is exactly what the earlier App Bundle & Signing lesson meant by "Play's backend slices the bundle" — the developer ships one .aab containing everything, and Play assembles the small, device-specific APK on demand.

Trimming Unused Densities & Languages Directly

Automatic splitting reduces what a single user downloads, but the source project can still be leaner. If RecipeBox's design only ships vector drawables (which scale to any density without needing per-density PNGs) and only officially supports English and Hindi, that can be declared explicitly.

// app/build.gradle (Groovy DSL)
android {
    defaultConfig {
        resConfigs "en", "hi"
    }
}
Explanation: resConfigs strips translated string resources for languages RecipeBox doesn't officially support (often pulled in transitively by libraries like AndroidX or Firebase, which ship dozens of locales) out of the build entirely, rather than just deprioritizing them per download.

Checking the Actual Size

After uploading a bundle, the Play Console's App size report (under Release → a specific release) shows the estimated download and install size across device configurations. Locally, Google's bundletool can do the same calculation before ever uploading anything.

// Generate device-specific APKs from a local .aab for testing
java -jar bundletool.jar build-apks \
  --bundle=app-release.aab \
  --output=recipebox.apks \
  --mode=universal

// Or inspect estimated sizes per device configuration
java -jar bundletool.jar get-size total --apks=recipebox.apks
Explanation: Building a universal APK from bundletool locally is also the quickest way to install and manually test a release bundle on a device without going through the Play Console at all.
With a right-sized bundle ready, the next lesson walks through actually getting RecipeBox in front of users: Publish to Play Store.