The Importance of Pragmatic Optimization in Mobile App Size
In the world of mobile app development, I often see that app size plays a critical role in a user's decision to download an application. Especially in regions with limited data plans or slow internet speeds, even a difference of a few megabytes can directly impact download rates. This situation constantly pushes developers to reduce app size, sometimes leading them to adopt incorrect strategies.
As someone who has been involved with systems and software for nearly twenty years, I've also worked on various mobile projects. Whether it was my own Android spam app or a client's Flutter-based mobile application, size optimization has always been a topic that comes up, but is often approached with one-dimensional solutions. In this post, I will share three fundamental misconceptions often made when optimizing mobile app size, and the lessons I've learned from these pitfalls.
Misconception 1: Focusing Only on the Code Stack for App Size
When it comes to reducing mobile app size, the first thing that usually comes to mind is the size of the compiled code. Developers immediately rush to tools like Proguard/R8 (for Android) or bitcode optimizations (for iOS). Yes, these tools can indeed provide significant reductions by eliminating unused code and optimizing existing code, but they are often only part of the picture. In my experience, the real reasons for an app's bloat are usually hidden elsewhere.
Especially when developing with cross-platform frameworks like Flutter or in Android/iOS projects that use native C++ libraries, a large portion of the app's total size can be made up of assets (images, videos, audio files, fonts) and native libraries (.so or .dylib files specific to an ABI). For example, in one of my mobile apps, when I forgot to manually check for native libraries compiled for multiple ABIs (ARMv7, ARM64, x86), the app's size unnecessarily increased by approximately 25 MB. While the modern Android App Bundle (AAB) format largely solves this problem, such details can be overlooked in older APK distributions or manual configurations.
ℹ️ ABI Support and Size
Android applications often contain native libraries compiled for multiple Application Binary Interfaces (ABIs). Each ABI supports a different CPU architecture. Your app including its own set of native libraries for every target ABI can significantly increase app size. While App Bundle solves this on a per-device basis, using
abiFiltersis critical for manual APK distributions.
Another major factor is high-resolution or unoptimized visual assets. In an ERP project, for the operator screens I developed, the icons and background images used for user interface elements were initially in PNG format and at a resolution higher than necessary. This caused visuals to make up more than 30% of the app's total size. With a simple WebP conversion and resolution optimization, we managed to reduce this size by more than half.
# Example command to analyze the content of an Android APK file
# This provides a general overview of file types and sizes within the APK.
# The 'assets/' and 'lib/' directories are often the biggest sources of bloat.
# apk-analyzer or Android Studio's APK Analyzer tool provides more detailed information.
# To extract an APK to a directory (just an example, actual tools may vary)
# unzip -l my_app.apk | awk '{print $NF, $1}' | sort -rh | head -n 10
# A structure similar to the output of Android Studio's APK Analyzer:
# Total Size: 65.2 MB
# ├── classes.dex: 8.5 MB (13.0%)
# ├── res/: 12.3 MB (18.9%)
# │ ├── drawable-xxhdpi/: 6.1 MB (9.4%)
# │ ├── mipmap-xxhdpi/: 3.2 MB (4.9%)
# │ └── ...
# ├── lib/: 24.7 MB (37.9%)
# │ ├── arm64-v8a/: 12.1 MB (18.6%)
# │ ├── armeabi-v7a/: 10.8 MB (16.6%)
# │ └── x86/: 1.8 MB (2.7%)
# ├── assets/: 15.1 MB (23.2%)
# │ ├── images/: 8.9 MB (13.7%)
# │ ├── fonts/: 4.2 MB (6.4%)
# │ └── ...
# └── META-INF/: 0.2 MB (0.3%)
# └── AndroidManifest.xml: 0.1 MB (0.2%)
As seen in the hypothetical analysis output above, the lib/ and assets/ directories make up more than 60% of the total size. This clearly demonstrates how insufficient focusing solely on code optimization can be. A true optimization effort requires a holistic approach that covers all these components.
Misconception 2: Manually Compressing Everything is Always Best
Acting with the "let's compress everything" mentality to reduce app size is also a common misconception. Especially for visuals or other media files, every developer tends to find and use their own compression tool. However, these manual compression processes can lead to both a waste of time and, in some cases, may not provide the expected benefit, or even negatively impact performance.
Modern build systems and distribution platforms (e.g., Google Play Store's AAB format) already offer advanced mechanisms to optimize your app's distribution size. AAB delivers optimized resources based on the device's language, screen density, and ABI, providing the user with only what they need. This reduces the developer's need to manually create different asset sets or deal with complex compression algorithms. In my experience, when we switched to AAB, an automatic reduction of 20-30% was achieved compared to the standard APK size.
⚠️ Risks of Manual Compression
Aggressively compressing manually can degrade visual quality or increase decompression time at runtime, negatively impacting the app's startup performance. Additionally, some compression algorithms may conflict with optimizations already applied by build systems and may not provide the expected benefit.
Regarding image compression, switching to modern formats like WebP instead of PNG or JPEG is generally a good step. WebP can offer the same visual quality with much smaller file sizes. However, a balance must be maintained here too. For example, converting very small icons to WebP might create millimeter differences in file size, but could cause additional CPU cycles for decompression. In a previous client project, while we were happy to "reduce the size" by converting every icon to WebP, we later noticed a micro-level increase in the app's startup time. This was because the decompression of hundreds of small WebP files collectively created a significant overhead.
// In Android's build.gradle (app level) file, eliminating unnecessary language and density resources with resConfigs
// This can be useful if you're not using AAB or want additional optimization.
android {
defaultConfig {
// ...
// Include only English and Turkish resources
resConfigs "en", "tr"
// Include only xhdpi and xxhdpi densities
// The rest are automatically distributed by the Play Store or not used on lower-end devices.
resConfigs "en", "tr", "xhdpi", "xxhdpi"
}
buildTypes {
release {
minifyEnabled true // Enable code shrinking
shrinkResources true // Remove unused resources
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}
The build.gradle configuration above provides an example of how we can automatically perform some resource optimizations without manual intervention. With resConfigs, we can specify which language and screen density resources should be included in the APK. Using such automatic optimizations can yield much more efficient and error-free results than manual efforts. The key is to understand the capabilities of the build system well and configure them correctly.
Misconception 3: Small App Size Equals High Performance Perception
This is perhaps one of the most insidious misconceptions. It's often thought that a small app download size directly implies good runtime performance. However, while these two metrics are related, they are not always directly proportional, and sometimes optimizing one may require sacrificing the other. An app's performance is determined not only by its file size but by many factors such as startup time, memory usage, CPU cycles, and the number and size of network requests.
In a mobile application we developed for a bank's internal platform, we initially adopted a "lazy-load" strategy for all assets and data to keep the app's download size as low as possible. The app size was indeed very small, but users encountered long loading times with every screen transition or initial launch. This was because every necessary asset or piece of data was fetched instantly over the network. This situation severely degraded the user experience, especially under poor network conditions.
💡 Performance-Oriented Size Optimization
When optimizing app size, it's crucial to focus not only on the download size but also on runtime metrics such as app startup time (cold start), inter-screen transition performance, and memory usage. Sometimes a slightly larger app can offer a much smoother user experience by pre-loading necessary resources.
To solve this problem, we chose to package critical assets and data to be displayed on initial launch within the application or cache them. The app size increased slightly, but the startup time was reduced by 40%, and users experienced a much smoother interface. This experience showed me that an obsession with "small size" can sometimes lead to neglecting user experience. I had done a more detailed analysis on [related: mobile app performance optimization].
// adb command to inspect memory usage on Android
// This command shows detailed instantaneous memory usage of an application.
// The "Native Heap", "Dalvik Heap", and "ART Heap" sections are particularly important.
adb shell dumpsys meminfo com.example.myapp
# Excerpt from example output:
# Total PSS (RAM): 125 MB
# Dalvik Heap: 30 MB (30 MB private dirty, 0 MB shared clean)
# Native Heap: 45 MB (45 MB private dirty, 0 MB shared clean)
# ART Heap: 20 MB (20 MB private dirty, 0 MB shared clean)
# ...
# These outputs help you understand which components of your app consume how much memory.
# Large images, memory leaks, or inefficient data structures can bloat the native/dalvik heap.
The adb dumpsys meminfo output above is a critical tool for monitoring an app's runtime memory usage. Sometimes an app with a small download size can consume too much memory at runtime, leading to device slowdowns or app crashes. Therefore, when making optimization decisions, it's necessary to look at all resource consumption during use, not just the download size.
Pragmatic Solutions and Strategies
With the lessons learned from these misconceptions, I've developed a more balanced and pragmatic approach to mobile app size optimization. Here are some strategies I apply:
- Comprehensive Size Analysis: The first step should always be a comprehensive analysis. Tools like Android Studio's APK Analyzer or Xcode's Build Reports clearly show how much space each component of your app occupies. This analysis should include not only code but also assets, native libraries, and resources. Especially if you're using AAB, it's beneficial to review Play Store's own size reports.
- Automate Asset Optimization: Avoid manual processes for optimizing visual and media assets. Prefer modern formats like WebP, AVIF, and integrate these conversions into your build process. For example, by adding tools like
imageminto your CI/CD pipeline, you can ensure that visuals are automatically optimized with every commit. I detailed the image optimization processes I used for a side product's website in the [related: website image optimization] post. - Dynamic Feature Modules: Features like Android's Dynamic Feature Modules and iOS's On-Demand Resources (ODR) offer the ability to download certain parts of the app only when needed. This significantly reduces the initial download size, allowing users to access the app faster. In a client project, we reduced the initial download size by 15% by making rarely used reporting modules dynamic.
- Native Library Management: Use
abiFiltersto eliminate unnecessary ABIs or let AAB handle this for you. If you're developing your own native libraries, include only the functions truly needed and optimize compilation options. From what I've seen, native libraries compiled with an "everything included" mentality often grow to large sizes. - Monitor Runtime Performance Metrics: While reducing app size, continuously monitor runtime performance metrics such as app startup time, memory usage, and CPU consumption. Firebase Performance Monitoring or similar tools will provide valuable data in this regard. Remember, the ultimate goal is to provide a fluid and enjoyable user experience, not just to reduce download size.
Lessons and Next Steps
Mobile app size optimization is not a one-time task but an ongoing process throughout the app's lifecycle. In my twenty years of experience, I've always found myself doing things wrong, then going back and fixing them. The important thing is not to shy away from making these mistakes and to learn a lesson from each one. For example, last month in a Flutter project, I realized that a single APK was unnecessarily bloated because I forgot to use the flutter build apk --split-per-abi command. Although it's a simple command, it can be overlooked due to a lack of automation.
In my future projects, I will continue to develop mobile applications, especially in areas such as AI-powered operations and production planning. In these projects, managing model sizes and the data sets required for RAG (Retrieval-Augmented Generation) will make app size even more complex. Therefore, I plan to more actively use approaches like dynamic feature modules to lazy-load AI models and data.
Developments in mobile platforms require us to continuously evolve our optimization approaches. New compression algorithms, new distribution formats, and increasing device processing power offer us more options. However, finding the right balance among these options still relies on the developer's experience and analytical skills.
Conclusion: A Balanced Approach is Essential
When optimizing mobile app size, getting fixated solely on the size of compiled code or visual assets prevents us from seeing the whole picture. Furthermore, trying to manually compress everything or assuming that a small size will always provide the best performance can also mislead us. True optimization is possible with a balanced approach that covers all components of the app, utilizes the capabilities of build systems, and centers on user experience.
For me, it's important to consider not only the impact of an optimization decision on a single metric but also its potential effects on all other metrics. App size can be a starting point, but the ultimate goal is always to deliver a fast, fluid, and user-friendly application. I will continue to pursue this balance.
Top comments (0)