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:
- APK size increase warning - Bundle was larger than necessary
- Missing native debug symbols - Crash reports harder to analyze
Results
| Metric | Before | After | Improvement |
|---|---|---|---|
| Release bundle size | ~85 MB | ~60 MB | ~30% smaller |
| Native debug symbols | Missing | Full | Google Play compliant |
| Supported architectures | 4 (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
| Architecture | Description | Included |
|---|---|---|
arm64-v8a | 64-bit ARM (modern devices) | Yes |
armeabi-v7a | 32-bit ARM (older devices) | Yes |
x86_64 | 64-bit Intel (emulators) | No |
x86 | 32-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 defaultNative 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 Symbols | With Debug Symbols |
|---|---|
| Crash stack traces show memory addresses | Crash traces show function names |
| Hard to identify crash location | Easy to pinpoint exact line |
| Manual symbol lookup required | Automatic deobfuscation |
Google Play Integration
Debug symbols are automatically uploaded when publishing to Google Play:
- Build creates
.native.symfiles - Upload occurs during
bundleReleasetask - Google Play Console stores symbols
- 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
| Architecture | Market Share | Status |
|---|---|---|
| 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)
Related Documentation
- Camera Debug Infrastructure (uses native TFLite library)
- CD Workflows
Last Updated: 2025-12-21 PR: #375