Google has released a game-changing feature in Android Gradle Plugin 8.12.0: optimized resource shrinking. This advancement can reduce app sizes by over 50% for apps with shared resources, making apps smaller, faster, and more efficient.
What is Resource Shrinking?
Resource shrinking is an Android build optimization that removes unused resources from your app's APK or AAB (Android App Bundle). This includes:
- Unused images, layouts, and drawables
- Alternative resources for different screen densities and configurations
- Strings and other assets that aren't referenced by your code
Traditionally, resource shrinking has been a separate step from code optimization. But that's changing.
Resource Types That Can Be Removed
| Resource Type | Examples | Typical Impact |
|---|---|---|
| Drawables | PNG, JPEG, WebP, Vector drawables | High (images are often largest) |
| Layouts | XML layout files | Medium |
| Strings | Unused translations, labels | Low-Medium |
| Colors/Themes | Unused color definitions, styles | Low |
| Raw Assets | Fonts, audio, video files | High (media files) |
| Alternative Resources | hdpi, xhdpi, xxhdpi variants | Very High (duplicates) |
The Problem with Traditional Resource Shrinking
Until now, resource shrinking had a significant limitation: AAPT2 (Android Asset Packaging Tool 2) generated unconditional keep rules that prevented R8 from fully optimizing both code and resources together.
This meant:
- Code that referenced unused resources couldn't be removed
- Resources that were only used by unused code remained in the app
- The optimization process wasn't as effective as it could be
Introducing Optimized Resource Shrinking
The new optimized resource shrinking approach, introduced in Android Gradle Plugin 8.12.0, solves this problem by fully integrating resource shrinking with code optimization in the R8 pipeline.
Traditional vs Optimized: Key Differences
| Aspect | Traditional Shrinking | Optimized Shrinking |
|---|---|---|
| Processing | Separate steps (code → resources) | Unified R8 pipeline |
| AAPT2 Keep Rules | Unconditional (blocks optimization) | Eliminated (full optimization) |
| Accuracy | Misses code-resource circular deps | Detects all unused items |
| Size Reduction | Moderate (20-30%) | High (50%+ possible) |
| Build Time | Baseline | Comparable (slight increase) |
How It Works
Instead of treating resource and code optimization as separate steps, the new system:
- Analyzes code and resources together in the R8 optimization pipeline
- Eliminates unconditional keep rules generated by AAPT2
- Identifies unused code and resources more precisely
- Removes both simultaneously for maximum efficiency
This holistic approach enables more aggressive optimization without compromising app functionality.
Impressive Performance Results
Google tested the new system on real-world apps, and the results are impressive:
Over 50% app size reduction for apps with shared resources
The Androidify sample app demonstrated significant improvements, showing how effective this optimization can be for production applications.
How to Enable Optimized Resource Shrinking
Step 1: Enable Minification and Resource Shrinking
First, ensure your release build has minification and resource shrinking enabled in your build.gradle file:
Kotlin DSL (build.gradle.kts):
android {
buildTypes {
release {
isMinifyEnabled = true
isShrinkResources = true
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}
}
Groovy (build.gradle):
android {
buildTypes {
release {
minifyEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}
Step 2: Enable Optimized Resource Shrinking
Add this line to your gradle.properties file:
android.r8.optimizedResourceShrinking=true
Step 3: Configure ProGuard Rules (If Needed)
Sometimes you need to keep specific resources that are referenced dynamically. Create or update proguard-rules.pro:
# Keep resources referenced by name at runtime
-keep class **.R$*
-keepclassmembers class **.R$* {
public static <fields>;
}
# Keep specific drawable resources
-keep class **.R$drawable {
public static final int splash_logo;
public static final int app_icon_*;
}
# Keep all resources from a specific module
-keep class com.yourapp.core.R$* {
*;
}
Step 4: Verify Configuration
Build your release APK/AAB and verify shrinking is active:
./gradlew assembleRelease --info
Look for log lines containing:
Shrinking resourcesR8: Optimized resource shrinking enabled
That's it! Your app will now benefit from the optimized resource shrinking pipeline.
Advanced Configuration: Keep Files
For fine-grained control, create a res/raw/keep.xml file:
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools"
tools:keep="@layout/legacy_screen,@drawable/brand_logo*"
tools:discard="@layout/unused_*,@drawable/test_*" />
This allows you to:
- Keep specific resources even if unused
- Discard specific resources even if referenced (use with caution!)
- Use wildcards (
*) for pattern matching
What This Means for Your App
Smaller APK/AAB Sizes
Less storage space required on user devices and faster downloads, especially important for users on limited data plans.
Improved Installation Speed
Smaller app sizes mean faster installation times, reducing user drop-off during downloads.
Better Performance
Less code and fewer resources to load means faster app startup and improved runtime performance.
Reduced Bandwidth Costs
For developers distributing apps, smaller packages mean lower bandwidth costs and faster delivery.
When Does This Become Standard?
While currently opt-in via the Gradle property, optimized resource shrinking will become the default behavior in Android Gradle Plugin 9.0.0.
This gives developers time to:
- Test the new optimization with their apps
- Identify any edge cases or issues
- Prepare for the transition before it becomes standard
Best Practices
1. Test Thoroughly
After enabling optimized resource shrinking, thoroughly test your app to ensure all necessary resources are retained and your app functions correctly.
2. Use ProGuard/R8 Rules Wisely
If you have custom ProGuard or R8 rules that explicitly keep resources, review them to ensure they don't conflict with the new optimization.
3. Monitor APK/AAB Size
Use Android Studio's APK Analyzer to examine your app before and after enabling the optimization to understand the impact.
Using APK Analyzer to Measure Impact
Step-by-Step Analysis
1. Build Two APKs:
# Build WITHOUT optimized shrinking
./gradlew assembleRelease
# Copy APK to backup
cp app/build/outputs/apk/release/app-release.apk app-before.apk
# Enable optimized shrinking in gradle.properties
echo "android.r8.optimizedResourceShrinking=true" >> gradle.properties
# Build WITH optimized shrinking
./gradlew clean assembleRelease
cp app/build/outputs/apk/release/app-release.apk app-after.apk
2. Open APK Analyzer:
- In Android Studio: Build > Analyze APK...
- Select your APK file
3. Compare Results:
You'll see a breakdown like this:
Before Optimization:
Total Size: 25.4 MB
├── res/ 12.3 MB (48%)
│ ├── drawable/ 8.1 MB
│ ├── layout/ 2.2 MB
│ └── other/ 2.0 MB
├── classes.dex 8.9 MB (35%)
├── lib/ 3.2 MB (13%)
└── other/ 1.0 MB (4%)
After Optimization:
Total Size: 13.8 MB (↓46%)
├── res/ 4.2 MB (30%) ← Reduced by 66%
│ ├── drawable/ 2.1 MB ← Removed 6 MB
│ ├── layout/ 1.0 MB ← Removed 1.2 MB
│ └── other/ 1.1 MB ← Removed 0.9 MB
├── classes.dex 6.1 MB (44%) ← Reduced by 31%
├── lib/ 2.8 MB (20%)
└── other/ 0.7 MB (6%)
Key Metrics to Check:
- res/ folder size - Should decrease significantly
- classes.dex size - Dead code removal
- Download size - What users actually download (AAB is compressed)
4. Check Resource References
Ensure resources are referenced directly in code rather than through string manipulation, which can make them appear unused to the optimizer.
5. Test on Multiple Configurations
Test your app on different device configurations to ensure resources for all screen densities and sizes are handled correctly.
Compatibility and Requirements
- Minimum Version: Android Gradle Plugin 8.12.0
- Build System: Compatible with both APK and AAB builds
- R8: Requires R8 code shrinker (enabled by default in modern Android projects)
Example Impact: Androidify Sample App
Google demonstrated the optimization on the Androidify sample app, showing measurable size reductions. While specific numbers vary by app, the general pattern is:
Apps with many shared resources → Larger size reductions
Apps with minimal shared resources → Moderate size reductions
The key is that the optimization is intelligent—it only removes what's truly unused.
Troubleshooting Common Issues
Issue 1: App Crashes After Enabling Shrinking
Symptom: App crashes with Resources$NotFoundException
Cause: Resources loaded dynamically via string names are being removed
Solution:
// ❌ Bad: Dynamic resource loading (will be removed)
val resId = resources.getIdentifier("img_$category", "drawable", packageName)
// ✅ Good: Direct reference (won't be removed)
val resId = when(category) {
"food" -> R.drawable.img_food
"travel" -> R.drawable.img_travel
else -> R.drawable.img_default
}
Or add to keep.xml:
<resources xmlns:tools="http://schemas.android.com/tools"
tools:keep="@drawable/img_*" />
Issue 2: Resources Still Not Removed
Symptom: Expected resource reduction didn't happen
Possible Causes & Solutions:
- Minification not enabled:
// Must have BOTH enabled
isMinifyEnabled = true // Required
isShrinkResources = true
- **Resources referenced in manifes
t:**
<!-- AndroidManifest.xml keeps these resources -->
<application android:icon="@drawable/ic_launcher" />
- Check build logs:
./gradlew assembleRelease --info | grep -i "shrink"
Issue 3: Build Fails After Enabling Optimization
Symptom: Build error: Resource shrinking failed
Solution: Check for:
- Corrupted resource files (malformed XML)
- Duplicate resource names across modules
- Invalid keep.xml syntax
# Clean and rebuild
./gradlew clean
./gradlew assembleRelease --stacktrace
Issue 4: Specific Resources Missing in Production
Symptom: Some images/layouts work in debug but not release
Solution: Resources used only in debug builds need special handling:
// build.gradle.kts
buildTypes {
debug {
// Debug resources are kept automatically
}
release {
// Explicitly keep debug-related resources if needed
resValue("string", "debug_mode", "false")
}
}
Or use tools:keep:
<resources xmlns:tools="http://schemas.android.com/tools"
tools:keep="@layout/debug_panel,@drawable/debug_*" />
Migration Tips
If you're currently using resource shrinking without the optimization:
- Upgrade to AGP 8.12.0 or higher
- Add the Gradle property to enable optimized shrinking
- Build your release APK/AAB and test thoroughly
- Compare app sizes before and after using APK Analyzer
- Monitor crash reports during initial rollout to catch any issues
- Test dynamic resource loading - Check all code that loads resources by name
- Verify all app features - Some resources may only be used in specific flows
The Technical Advantage
By integrating resource shrinking directly into the R8 pipeline, Google has eliminated a major bottleneck in app optimization. This unified approach allows for:
- Dead code elimination that considers resource usage
- Dead resource elimination that considers code references
- Circular dependency resolution between code and resources
- More accurate analysis of what's actually used
Looking Forward
Optimized resource shrinking represents a significant advancement in Android app optimization. As it becomes the standard in AGP 9.0.0, developers can expect:
- Even smaller app sizes across the ecosystem
- Faster app performance as a baseline
- Better user experiences, especially on lower-end devices
- Reduced storage pressure on user devices
Try It Today
With Android Gradle Plugin 8.12.0 available now, there's no reason not to test optimized resource shrinking. The potential for significant app size reduction makes it worth the effort.
For complete technical details and implementation guidance, read the full announcement by Johan Bay (Software Engineer) on the Android Developers Blog.
Have you tried optimized resource shrinking in your apps? Share your results with us on social media!