APK Size Optimization

Build configuration changes to reduce production APK size and improve Google Play compliance.

Status: ✅ Implemented (PR #375) Location: app/build.gradle.kts


Overview

The optimization addresses two Google Play Console warnings:

  1. APK size increase warning - Bundle was larger than necessary
  2. Missing native debug symbols - Crash reports harder to analyze

Results

MetricBeforeAfterImprovement
Release bundle size~85 MB~60 MB~30% smaller
Native debug symbolsMissingFullGoogle Play compliant
Supported architectures4 (ARM + x86)2 (ARM only)Reduced surface area

ABI Filtering

What Changed

Release builds now only include ARM architectures:

// app/build.gradle.kts
android {
    buildTypes {
        release {
            ndk {
                abiFilters += listOf("armeabi-v7a", "arm64-v8a")
            }
        }
    }
}

Architecture Details

ArchitectureDescriptionIncluded
arm64-v8a64-bit ARM (modern devices)Yes
armeabi-v7a32-bit ARM (older devices)Yes
x86_6464-bit Intel (emulators)No
x8632-bit Intel (emulators)No

Why Remove x86/x86_64?

  • x86 architectures are emulator-only - No production Android phones use Intel chips
  • ARM devices are 99.9%+ of market - All major Android phones and tablets
  • Significant size savings - Each architecture adds ~10-15 MB of native libraries

Debug Builds

Debug builds still include all architectures for emulator testing:

// Only release builds have ABI filters
// Debug builds include all architectures by default

Native Debug Symbols

What Changed

Release builds now upload full debug symbols:

// app/build.gradle.kts
android {
    buildTypes {
        release {
            ndk {
                debugSymbolLevel = "FULL"
            }
        }
    }
}

Why This Matters

Without Debug SymbolsWith Debug Symbols
Crash stack traces show memory addressesCrash traces show function names
Hard to identify crash locationEasy to pinpoint exact line
Manual symbol lookup requiredAutomatic deobfuscation

Google Play Integration

Debug symbols are automatically uploaded when publishing to Google Play:

  1. Build creates .native.sym files
  2. Upload occurs during bundleRelease task
  3. Google Play Console stores symbols
  4. Crash reports show deobfuscated stack traces

Firebase Crashlytics

Mapping file upload is also enabled for Crashlytics:

android {
    buildTypes {
        release {
            configure<CrashlyticsExtension> {
                mappingFileUploadEnabled = true
            }
        }
    }
}

This ensures both Google Play Console and Firebase Crashlytics can deobfuscate crash reports.


Build Commands

Debug Build (All Architectures)

./gradlew assembleDebug
# Includes: arm64-v8a, armeabi-v7a, x86_64, x86
# Size: ~120 MB (for emulator compatibility)

Release Bundle (ARM Only)

./gradlew bundleRelease
# Includes: arm64-v8a, armeabi-v7a
# Size: ~60 MB (optimized for production)

Check APK Contents

# Unzip the APK to see included architectures
unzip -l app-release.apk | grep "\.so"
# Should only show: lib/arm64-v8a/ and lib/armeabi-v7a/

Compatibility

Device Coverage

ArchitectureMarket ShareStatus
ARM64 (arm64-v8a)~85%Supported
ARM32 (armeabi-v7a)~15%Supported
Intel x86/x86_64<0.1%Not supported

Minimum Requirements

  • minSdk: 31 (Android 12)
  • targetSdk: 36 (Android 15)

Since minSdk is 31, all supported devices are ARM-based. No production users are affected by removing x86 support.


Troubleshooting

Emulator Won’t Install Release Build

Symptom: Release APK fails to install on emulator

Cause: Release builds only include ARM architectures

Solution: Use debug builds for emulator testing, or create an ARM emulator image

Missing Native Crashes in Google Play

Symptom: Crash reports show raw addresses instead of function names

Cause: Debug symbols not uploaded

Solution: Ensure bundleRelease completes successfully (symbols upload at build time)



Last Updated: 2025-12-21 PR: #375