Skip to content
All posts
June 28, 20263 min read

How to Cut Your APK/AAB Size by 40% Using R8 and ProGuard

App size affects install conversion rates, storage permissions, and Play Store ranking. Here's a systematic approach to shrinking your Android app using R8, resource shrinking, and build configuration.

AndroidPerformanceGradleR8
Share:

App size is a distribution metric as much as a technical one. Every extra megabyte increases the chance a user uninstalls during a storage crunch or skips the install entirely. On Play Store, size affects conversion rates on low-end devices and emerging markets.

Here's how to cut it systematically.

Start with a size breakdown

Before touching anything, understand where the bytes are:

bash
# Generate an APK analyzer report
./gradlew assembleRelease
# Then open the APK in Android Studio: Build > Analyze APK

The breakdown will show: DEX code, resources, assets, native libs. You need to know which category is largest before you optimize.

Enable R8 — the right way

R8 is the default shrinker in AGP 3.4+, but full optimization mode requires explicit configuration:

kotlin
// build.gradle.kts
android {
    buildTypes {
        release {
            isMinifyEnabled = true
            isShrinkResources = true
            proguardFiles(
                getDefaultProguardFile("proguard-android-optimize.txt"),
                "proguard-rules.pro"
            )
        }
    }
}

code
proguard-android-optimize.txt
enables more aggressive optimizations than
code
proguard-android.txt
. Use it.

code
isShrinkResources = true
removes unused resources. It requires
code
isMinifyEnabled = true
to be set first.

ProGuard rules — what to keep

R8 strips everything it thinks is unreferenced. That breaks reflection-heavy libraries. Add keep rules for:

proguard
# Kotlin serialization
-keepattributes *Annotation*, InnerClasses
-dontnote kotlinx.serialization.AnnotationsKt

# Room entities
-keep class * extends androidx.room.RoomDatabase
-keep @androidx.room.Entity class *

# Hilt
-keep class dagger.hilt.** { *; }
-keep class javax.inject.** { *; }

# Your data classes used with serialization
-keep class com.yourpackage.data.model.** { *; }

The rule: if something uses reflection, annotation processing, or dynamic class loading — keep it.

Resource shrinking beyond the basics

Resource shrinking removes unused drawables, layouts, and strings. Make it more aggressive:

xml
<!-- res/raw/keep.xml -->
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools"
    tools:discard="@layout/unused_layout,@drawable/old_icon"
    tools:keep="@layout/definitely_needed" />

For apps targeting specific screen densities, strip unused density buckets:

kotlin
android {
    defaultConfig {
        resConfigs("en", "xxhdpi")
    }
}

This alone can cut 15–20% from resource-heavy apps.

Remove unused native libraries

If you're using libraries that ship with native

code
.so
files for multiple ABIs, configure your build to only include what you ship:

kotlin
android {
    splits {
        abi {
            isEnable = true
            reset()
            include("arm64-v8a", "armeabi-v7a")
            isUniversalApk = false
        }
    }
}

With AAB on Play Store, this happens automatically. But for direct APK distribution, it matters.

Image optimization

Switch from PNG to WebP for all non-vector images. Android Studio can batch-convert: right-click folder > Convert to WebP. Typical savings: 30–50% per image.

For icons and simple graphics: use Vector Drawables (SVG-like XML). Zero size scaling, tiny file size.

Dependency audit

Some dependencies bring significantly more than their advertised size:

bash
./gradlew dependencies --configuration releaseRuntimeClasspath

Look for libraries you're barely using. If you're importing all of Apache Commons for one utility method, copy the method instead.

Measure before and after

Track AAB/APK size per release in a spreadsheet or script. Knowing your baseline makes every optimization measurable.

The actual 40% figure: it comes from combining R8 full mode + resource shrinking + density filtering + WebP conversion. None of these alone gets you there. Together they compound.

Start with R8 and resource shrinking — that's the 80% solution. Add the rest if you need to squeeze further.

Share:
S

Sudarshan Chaudhari

AI Systems Builder / Product Engineer

Bangkok, Thailand

Solo Android developer with 13+ years in QA, building Android apps, AI automation systems, and developer tools at SudarshanTechLabs.

Stay updated

Get new posts on Android, Kotlin, and solo dev straight to your inbox.

Newsletter preferences

Related Apps

MyFamilyTracker

Real-time family location sharing — Firebase Realtime DB for sub-second propagation, WorkManager + ForegroundService for OS-compliant background collection, geofencing via Google Maps API.

Building something? Available for Android dev and QA consulting.

Work with me

Comments — powered by Giscus

Apps tagged with this