Tweak to Reduce the Size of APK
A few days ago, I started a new Blank Native Mobile App project using Mendix Studio Pro and immediately generated an APK to test a new automated script to build APKs/AABs/IPAs I’m working on. To my surprise, the generated APK was more than double its usual file size. This procedure presents a way to fix this issue.
The issue
In the image below, we can see the file size of the APK Debug built from the Mendix-generated React Native project files. It has 185MB, more than twice the usual size I was used to remembering!
Is this really an issue? Well, if you intend to generate nightly build APKs from your project in order to perform automated tests, and you need to store the APKs generated. The smaller the file size, the better.
For distribution in the app stores, the Google Play Store requires the AAB (Android App Bundle) type format. AABs allow Google Play to deliver only the necessary components for a specific device, resulting in smaller downloads, faster installations, and less storage space used. So the AAB file size isn’t a concern here.
The Rationale
Looking for more info, I’ve found these references:
- Android Gradle Plugin 3.6.0: Native libraries packaged uncompressed by default:
When you build your app, the plugin now sets
extractNativeLibsto"false"by default. That is, your native libraries are page aligned and packaged uncompressed. While this results in a larger upload size, your users benefit from the following:• Smaller app install size because the platform can access the native libraries directly from the installed APK, without creating a copy of the libraries.
• Smaller download size because Play Store compression is typically better when you include uncompressed native libraries in your APK or Android App Bundle.
- The text above mentions the property
extractNativeLibs. The Android Documentation says:
This attribute indicates whether the package installer extracts native libraries from the APK to the file system. If set to
"false", your native libraries are stored uncompressed in the APK. Although your APK might be larger, your application loads faster because the libraries load directly from the APK at runtime.The default value of
extractNativeLibsdepends onminSdkVersionand the version of AGP you're using. In most cases, the default behavior is probably what you want, and you don't have to set this attribute explicitly
- Android Gradle Plugin 4.2.0: Use the DSL to package compressed native libraries:
We recommend packaging native libraries in uncompressed form, because this results in a smaller app install size, smaller app download size, and faster app loading time for your users. However, if you want the Android Gradle plugin to package compressed native libraries when building your app, set
useLegacyPackagingtotruein your app'sbuild.gradlefile.
This is something weird, since the AGP 3.6.0 and AGP 4.2.0 are both very old, and we should have identified this increase in the file size a long time ago.
Consulting the Mendix Support:
The reason for the increased apk file size is due to the updated the
minSdkVersionfrom Native Template v7.0.20 onwards.
Native Template v7.0.17 containsminSdkVersion= 21 while v7.0.25 containsminSdkVersion= 23. FromminSdkVersion23, the APK includes libraries for all ABIs which leads to this significant increase.
So this is expected.
This makes sense! Recently, Mendix R&D increased the minSdkVersion from 21 to 23, and as a consequence, we have the APK file size increase as a collateral effect.
Looking further, this post in the Google IssueTracker:
Starting with M, the platform can read the so files directly inside the APK without extracting them, saving storage space.
Right now we compress if the manifest attribute extractNativeLibs is true or not present. If the attribute is not present and minSdkVersion is M+, then we should not compress.
If you don’t remember, Android API Level 23 is the Android Marshmallow (Android M).
The Solution
If you prefer to keep the previous behaviour, that is, keep the Native Libs compressed, the fix is very easy:
- [1] Open your
applevelbuild.gradlefile. - [2] Add the following inside the
androidscope:
android {
//...
packagingOptions {
jniLibs {
useLegacyPackaging true
}
}
}- [3] Rebuild your APK
.\gradlew.bat assembleAppstoreDebug --stacktrace- [4] Check the results. Now the APK file size is 71MB!
Comments and Conclusion
- As you could see, the fix to reduce the APK file size is easy, just define
useLegacyPackaging truein theandroid/packagingOptions/jniLibssection ofbuild.gradle. - Observe that, if you proceed with this fix, your app will become smaller in file size but slower in loading time. This is something I plan to investigate in a future article.
- This fix is not relevant if you intend to generate the AAB and publish your app in the Google Play Store.
- Worth mentioning that while the APK Release has ~42MB, even with this fix, the IPA file size (to be used in iOS devices) is ~ 9MB 🤯!!
- I hate to say it, but in a way I love bugs, as I learn a lot from them in the challenge of finding a solution!
If you find an error or have a suggestion, please let me know in the comments!😉
References
Android Studio | Android Developers
Release notes of Android Gradle Plugin 4.2.0
developer.android.com
