Gradle Configuration for Density and Size Optimization
1. Base build.Gradle (Module) Configuration
android {
compileSdk 34
defaultConfig {
applicationId "com.example.app"
minSdk 21
targetSdk 34
versionCode 1
versionName "1.0"
// Enable code shrinking and obfuscation
shrinkResources true
minifyEnabled true
// Configure ProGuard rules
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
buildTypes {
release {
// Size optimization settings
crunchPngs true // Compress PNG files
isDebuggable = false
isJniDebuggable = false
isRenderscriptDebuggable = false
// Enable resource shrinking
shrinkResources true
minifyEnabled true
}
debug {
shrinkResources false
minifyEnabled false
crunchPngs false
}
}
// Configure splits for different densities and ABIs
splits {
density {
enable true
exclude "ldpi", "tvdpi"
compatibleScreens 'small', 'normal', 'large', 'xlarge'
}
abi {
enable true
reset()
include "armeabi-v7a", "arm64-v8a", "x86", "x86_64"
universalApk true
}
}
// Bundle configuration for AAB
bundle {
density {
// Enable split by screen density
enableSplit true
}
abi {
enableSplit true
}
language {
enableSplit true
}
}
// Enable build features wisely
buildFeatures {
viewBinding true
buildConfig true
// Only enable what you need
// compose false
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = "1.8"
}
// Configure packaging options to exclude unnecessary files
packagingOptions {
resources {
excludes += [
'META-INF/*.kotlin_module',
'META-INF/*.version',
'META-INF/proguard/*',
'META-INF/*.properties',
'META-INF/services/*',
'**/*.kotlin_builtins',
'**/*.kotlin_metadata'
]
pickFirsts += [
'lib/*/libc++_shared.so'
]
}
}
}
dependencies {
implementation 'androidx.core:core-ktx:1.12.0'
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'com.google.android.material:material:1.11.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
// Use specific version instead of +
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
// Debug only dependencies
debugImplementation 'com.facebook.stetho:stetho:1.6.0'
// Test dependencies
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
}
2. settings.gradle Configuration
pluginManagement {
repositories {
google()
mavenCentral()
gradlePluginPortal()
}
resolutionStrategy {
eachPlugin {
if (requested.id.id == 'com.android.application') {
useModule('com.android.tools.build:gradle:8.2.2')
}
if (requested.id.id == 'org.jetbrains.kotlin.android') {
useModule('org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.22')
}
}
}
}
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
// Only add custom repositories if absolutely necessary
// maven { url 'https://jitpack.io' }
}
}
rootProject.name = "MyApp"
include ':app'
3. ProGuard Rules (proguard-rules.pro)
# Basic Android rules
-keep class android.support.annotation.Keep
-keep @android.support.annotation.Keep class * {*;}
# Keep application class
-keep public class * extends android.app.Application
# Keep activities, services, broadcast receivers
-keep public class * extends android.app.Activity
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider
# Keep view bindings
-keep class * implements android.view.ViewBinding { *; }
# Keep parcelable classes
-keep class * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator *;
}
# Keep serializable classes
-keepclassmembers class * implements java.io.Serializable {
static final long serialVersionUID;
private static final java.io.ObjectStreamField[] serialPersistentFields;
private void writeObject(java.io.ObjectOutputStream);
private void readObject(java.io.ObjectInputStream);
java.lang.Object writeReplace();
java.lang.Object readResolve();
}
# Keep Retrofit
-keep class retrofit2.** { *; }
-keepclasseswithmembers class * {
@retrofit2.http.* <methods>;
}
# Keep GSON
-keep class com.google.gson.** { *; }
-keep class com.google.gson.stream.** { *; }
-keep class * implements com.google.gson.TypeAdapterFactory
-keep class * implements com.google.gson.JsonSerializer
-keep class * implements com.google.gson.JsonDeserializer
# Remove logging in release
-assumenosideeffects class android.util.Log {
public static *** d(...);
public static *** v(...);
public static *** i(...);
public static *** w(...);
public static *** e(...);
}
# Optimizations
-optimizations !code/simplification/arithmetic,!code/simplification/cast,!field/*,!class/merging/*
-optimizationpasses 3
-allowaccessmodification
4. Advanced Size Optimization Techniques
Custom Density Configuration
android {
// Limit supported screen densities
defaultConfig {
resConfigs "en", "xxhdpi", "xxxhdpi"
// Or exclude specific densities
resConfigs "mdpi", "hdpi", "xhdpi", "xxhdpi", "xxxhdpi"
}
}
Resource Shrinking Configuration
android {
buildTypes {
release {
// Keep specific resources
shrinkResources {
keepFiles 'raw/keep_this_file.txt'
keepFiles 'drawable/ic_launcher_foreground.xml'
}
}
}
}
5. Gradle Properties for Performance
gradle.properties:
# Enable build cache
org.gradle.caching=true
# Configure JVM for better performance
org.gradle.jvmargs=-Xmx4096m -XX:MaxMetaspaceSize=1024m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
# Parallel build execution
org.gradle.parallel=true
# Configure daemon
org.gradle.daemon=true
# Enable configuration on demand
org.gradle.configureondemand=true
# Kotlin compiler options
kotlin.code.style=official
kotlin.incremental=true
kotlin.parallel.tasks.in.project=true
6. Advanced ProGuard Rules for Specific Libraries
# For Firebase
-keep class com.google.firebase.** { *; }
-keep class com.google.android.gms.** { *; }
# For Glide
-keep public class * implements com.bumptech.glide.module.GlideModule
-keep public class * extends com.bumptech.glide.module.AppGlideModule
-keep public enum com.bumptech.glide.load.ImageHeaderParser$** {
**[] $VALUES;
public *;
}
# For Room
-keep class * extends androidx.room.RoomDatabase
-keep class * extends androidx.room.Entity
# For WorkManager
-keep class androidx.work.** { *; }
7. Build Variants and Product Flavors
android {
flavorDimensions "version"
productFlavors {
free {
dimension "version"
applicationIdSuffix ".free"
versionNameSuffix "-free"
// Limit resources for free version
resConfigs "en", "xxhdpi"
}
paid {
dimension "version"
applicationIdSuffix ".paid"
versionNameSuffix "-paid"
}
}
// Configure different settings for each variant
applicationVariants.all { variant ->
variant.outputs.each { output ->
def flavor = variant.productFlavors[0].name
output.outputFileName = "app-${flavor}-${variant.versionName}.apk"
}
}
}
8. Dependency Size Analysis
Add to build.gradle (project level):
plugins {
id 'com.android.application' version '8.2.2' apply false
id 'org.jetbrains.kotlin.android' version '1.9.22' apply false
id 'com.github.ben-manes.versions' version '0.50.0' // For dependency updates
}
// Task to analyze APK size
task analyzeApkSize {
doLast {
def apkFile = file("app/build/outputs/apk/release/app-release.apk")
if (apkFile.exists()) {
def sizeMB = apkFile.length() / (1024 * 1024)
println "APK Size: ${String.format("%.2f", sizeMB)} MB"
}
}
}
9. R8 Configuration (Alternative to ProGuard)
android {
buildTypes {
release {
// Enable R8 (default in newer versions)
minifyEnabled true
// R8 configuration file
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
// R8 specific rules
setProguardFiles([getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'])
}
}
}
Key Optimization Strategies:
- Density Splits: Split APK/AAB by screen density to reduce size
- Resource Shrinking: Remove unused resources automatically
- Code Shrinking: Remove unused code with ProGuard/R8
- PNG Compression: Compress images during build
- Selective Resource Inclusion: Only include necessary languages and densities
- Dependency Optimization: Use specific versions and remove unused dependencies
- Build Cache: Enable Gradle build caching for faster builds
This configuration will significantly reduce your APK/AAB size while maintaining functionality across different device densities.
