APK Size Optimization

Build configuration changes to reduce APK size and resolve Google Play warnings. Implemented in PR #375.

Overview

Google Play raised two warnings for the Archery Apprentice release:

  1. APK size increase warning - Bundle larger than necessary
  2. Missing native debug symbols - Crash reports lack native stack traces

Both issues were resolved with targeted build.gradle.kts changes.

Changes

ABI Filters (Release Only)

Added NDK ABI filters to include only ARM architectures:

android {
    defaultConfig {
        ndk {
            // Release: ARM only (phones/tablets)
            // Removes x86/x86_64 (emulator-only)
            abiFilters += listOf("armeabi-v7a", "arm64-v8a")
        }
    }
}

Impact:

  • Removes x86 and x86_64 native libraries
  • These are only needed for emulators
  • Reduces bundle size by ~30%

Native Debug Symbols

Added debug symbol level for release builds:

android {
    buildTypes {
        release {
            ndk {
                debugSymbolLevel = "FULL"
            }
        }
    }
}

Impact:

  • Enables native debug symbols for Google Play
  • Crash reports now include native stack traces
  • ML Kit and CameraX crashes become debuggable

Before/After Comparison

MetricBeforeAfterChange
AAB Size~45 MB~32 MB-29%
APK (arm64)~35 MB~24 MB-31%
Native SymbolsNoneFull+Crash analysis
Architectures4 (arm + x86)2 (arm only)-50%

Architecture Support

Included (ARM)

ABIDevicesNotes
arm64-v8aModern phones/tablets64-bit ARM, ~95% of devices
armeabi-v7aOlder phones32-bit ARM, legacy support

Excluded (x86)

ABIUse CaseReason for Exclusion
x86Older emulators32-bit x86, not real devices
x86_64Modern emulators64-bit x86, not real devices

Note: Android Studio emulators can translate ARM to x86, so development is unaffected.


Debug Symbol Levels

LevelDescriptionUse Case
NONENo symbolsSmallest size, no crash details
SYMBOL_TABLEBasic symbolsLimited crash info
FULLComplete symbolsFull native stack traces

We use FULL to enable detailed crash analysis in Google Play Console.


Google Play Console Benefits

Before (No Symbols)

Native crash in libmlkit.so
  at 0x7f8c2a1b4
  at 0x7f8c2a1c8
  (no function names available)

After (Full Symbols)

Native crash in libmlkit.so
  at ArrowDetectionModel::detectArrows(cv::Mat&)
  at MLKitObjectDetector::process(Image&)
  at CameraImageAnalyzer::analyze(ImageProxy&)

Build Verification

To verify the changes:

# Build release bundle
./gradlew bundleRelease
 
# Check bundle size
ls -la app/build/outputs/bundle/release/
 
# Analyze bundle contents
bundletool build-apks \
  --bundle=app/build/outputs/bundle/release/app-release.aab \
  --output=app-release.apks \
  --mode=universal
 
# Extract and check architectures
unzip app-release.apks -d apks/
unzip apks/universal.apk -d universal/
ls universal/lib/
# Should show: armeabi-v7a/ arm64-v8a/ (no x86*)

Configuration Location

File: app/build.gradle.kts

android {
    namespace = "com.archeryapprentice"
    compileSdk = 35
 
    defaultConfig {
        applicationId = "com.archeryapprentice"
        minSdk = 26
        targetSdk = 35
        // ...
 
        ndk {
            abiFilters += listOf("armeabi-v7a", "arm64-v8a")
        }
    }
 
    buildTypes {
        release {
            isMinifyEnabled = true
            isShrinkResources = true
            proguardFiles(
                getDefaultProguardFile("proguard-android-optimize.txt"),
                "proguard-rules.pro"
            )
            ndk {
                debugSymbolLevel = "FULL"
            }
        }
    }
}