Gradle Configuration

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:

  1. Density Splits: Split APK/AAB by screen density to reduce size
  2. Resource Shrinking: Remove unused resources automatically
  3. Code Shrinking: Remove unused code with ProGuard/R8
  4. PNG Compression: Compress images during build
  5. Selective Resource Inclusion: Only include necessary languages and densities
  6. Dependency Optimization: Use specific versions and remove unused dependencies
  7. 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.