Why App Size Matters
App size directly impacts downloads, installs, and retention:
- Apps over 200 MB require Wi-Fi on iOS (cellular download limit)
- A 10% increase in app size correlates with roughly 1-2% fewer installs
- Users in emerging markets with limited storage prioritize smaller apps
- Smaller apps install faster, improving first-time user experience
- App stores display the download size prominently in search results
Google Play enforces a 150 MB limit for APKs and recommends AABs stay under 200 MB. Apple allows up to 4 GB but imposes the cellular download limit at 200 MB.
Measuring App Size
Before optimizing, understand what contributes to your app's size:
iOS
- Xcode App Size Report: After archiving, select "Distribute App" and check the app thinning size report
- App Store Connect shows the actual download size per device variant after thinning
Android
- APK Analyzer in Android Studio: Visual breakdown of classes, resources, native libraries, and assets
- bundletool CLI: Generate device-specific APKs from an AAB and measure each variant
React Native / Flutter
- Metro bundler output shows JS bundle size (React Native)
- flutter build --analyze-size provides a detailed breakdown
iOS Optimization Techniques
App Thinning
Apple's app thinning system automatically creates device-specific variants:
- Slicing: Delivers only the resources (images, assets) relevant to the user's device
- Bitcode: Apple can recompile your app for specific architectures (deprecated in Xcode 14+)
- On-Demand Resources: Download assets only when needed (common in games)
Asset Catalogs
Use Xcode Asset Catalogs to store images. They support:
- Device-specific variants (@1x, @2x, @3x)
- Automatic slicing (only the relevant variant is downloaded)
- Vector assets (PDF or SVG) that scale without multiple sizes
Swift-Specific
- Enable Whole Module Optimization for release builds
- Remove unused code with the -dead_strip linker flag
- Strip debug symbols from release builds
Android Optimization Techniques
Android App Bundle (AAB)
Always publish AABs instead of APKs. Google Play generates optimized APKs for each device configuration:
- Only the matching screen density resources are included
- Only the relevant ABI (arm64-v8a, x86_64, etc.) is delivered
- Only the user's language resources are included
AABs typically save 15-30% compared to universal APKs.
R8 / ProGuard
R8 is Android's code shrinker and optimizer (replaced ProGuard as the default):
- Removes unused classes, methods, and fields
- Obfuscates code (shorter class/method names = smaller DEX files)
- Optimizes bytecode
Enable in build.gradle with minifyEnabled true for release builds. Maintain proper ProGuard rules for libraries that use reflection.
Resource Shrinking
Add shrinkResources true alongside minifyEnabled to remove unused resources (drawables, layouts, strings) that R8 cannot detect through code analysis.
Native Libraries
If you include native .so files:
- Use abiFilters to include only the architectures you need
- With AAB, this is handled automatically, but for APKs it matters
- Consider whether you need both arm64-v8a and armeabi-v7a (32-bit is being phased out)
Cross-Platform Tips
Images and Assets
- Use WebP instead of PNG for images (30-50% smaller with equivalent quality)
- Use vector graphics (SVG) wherever possible
- Compress images with tools like TinyPNG, ImageOptim, or Squoosh
- Lazy-load images from a CDN instead of bundling them
JavaScript Bundle (React Native)
- Enable Hermes (compiles JS to bytecode, reducing bundle size and improving startup)
- Use RAM Bundles or lazy loading for large apps
- Analyze your bundle with tools like react-native-bundle-visualizer
- Avoid importing entire libraries when you only need one function (tree shaking)
Flutter
- Enable --split-debug-info to separate debug symbols
- Use --obfuscate to reduce Dart code size
- Enable deferred components for on-demand feature loading
- Audit dependencies in pubspec.yaml and remove unused packages
General Strategies
- Audit dependencies regularly: Remove unused libraries. Each library adds weight.
- Use dynamic delivery: Load features on demand rather than bundling everything upfront.
- Compress audio and video: Use efficient codecs (AAC for audio, H.265 for video) and appropriate bitrates.
- Monitor over time: Track app size in your CI pipeline and set size budgets. Alert when a build exceeds the threshold.