blog content
The following article is part of The Ultimate Guide to React Native Optimization and describes how to optimize your Android application size with Gradle settings.
Why is it important?
The small size of the app makes a difference for several reasons. First, not everybody has the luxury of using the latest device and having a stable and fast internet connection. This group of users may not be able to download and run your big-size apps, which can significantly reduce the number of potential users of your products.
Second, the bigger the size, the bigger the app's startup time. It takes much more time to make your product ready for the first interaction with a user when it’s too big. And that can seriously harm the user experience of your product.
Third, you need to remember that the app usually takes up more space after the installation. In some cases, they may even not fit into the device’s storage. In such scenarios, users may decide to skip the installation to avoid deleting their existing apps.
In this article, we will tell you how to avoid these unpleasant consequences of building big-size apps. Continue reading to find out how to optimize your Android app’s size with Gradle settings.
In other blog posts based on The Ultimate Guide to React Native Optimization, we touch on the following performance-related topics:
- Optimizing your Android app startup time with Hermes
- Automating your dependency management with `Autolinking`
- Debugging faster and better with Flipper
- Why is it essential to always run the latest version of React Native?
- Experimenting with the New Architecture of React Native
Check them out! Now let's jump into the main topic.
Why do memory usage and size of your app matter?
At the beginning of each React Native project, you usually don’t care about the application size. After all, it is hard to make such predictions so early in the process. But it takes only a few additional dependencies for the application to grow from standard 5 MB to 10, 20, or even 50, depending on the codebase.
Should you really care about app size in the era of super-fast mobile internet and WiFi access everywhere? Why does bundle size grow so rapidly? We will answer those questions in the following few paragraphs but first, let’s look at what a typical React Native bundle is made of.
By default, React Native application on Android consists of:
- four sets of binaries compiled for different CPU architectures,
- directory with resources such as images, fonts etc.,
- JavaScript bundle with business logic and your React components,
- other files.
React Native offers some optimizations that allow you to improve the structure of the bundle and its overall size. But they are disabled by default.
If you are not using them effectively, especially when your application grows, you are unnecessarily increasing the overall size of your application in bytes. That can hurt the experience of your end-users.
Why is big APK size such a big deal?
The answer is simple. Larger APK means more time needed to download from the app store and more bytecode to load into memory. Let us explain what we mean in more detail.
It’s great that you and your team operate on the latest devices and have fast and stable access to the Internet. But you need to remember that not everyone has the same luxury. There are still parts of the world where network accessibility and reliability are far from perfect. Projects like Starlink promise to improve that situation, but that will take time.
Right now, there are still markets where every megabyte of traffic has its price. In those regions, the application’s size directly impacts the conversion and the installation/cancellation ratio increases along with the app size.
It is also a common belief that every well-crafted and carefully designed application not only provides a beautiful interface but is also optimized for the end device. Well – that is not always the case. And because the Android market is so competitive, there is a big chance that a smaller alternative to those beautiful yet large apps is already gaining more traction from the community.
Another important factor is device fragmentation. The Android market is very diverse in that respect. There are 20+ popular manufacturers, each releasing an array of devices every year. Contributing to a relatively significant share of mid to low-end devices, which account for over 60% of all smartphone sales annually. And those devices may face issues when dealing with bigger APKs.
As we have stressed out already, the startup time of your application is essential. The more code the device has to execute while opening up your code, the longer it takes to launch the app and make it ready for the first interaction.
Now, let’s move the last factor worth mentioning in this context – the device storage. Apps usually end up taking up more space after the installation. Sometimes they even may not fit into the device memory. In that situation, users may decide to skip installing your product if that would mean removing other resources such as applications or images.
Using Proguard for release builds to optimize app size
If the problem’s that you’re not enabling Proguard for release builds and creating APK with code for all CPU architectures, this shipping a larger APK, we would propose the following solution: flip the boolean flag enableProguardInReleaseBuilds to true, adjust Proguard rules to your needs and test release builds for crashes. Also, flip enableSeparateBuildPerCPUArchitecture to true. Now let’s dig a bit deeper.
Android is an operating system that runs on plenty of devices with different architectures, so your build must support most of them. React Native supports four: <rte-code>armeabi-v7a<rte-code>, <rte-code>arm64-v8a<rte-code>, <rte-code>x86<rte-code>, and <rte-code>x86_64<rte-code>.
While developing your application, Gradle generates the APK file that can be installed on any of the mentioned CPU architectures device. In other words, your APK (the file outputted from the build process) is actually four separate applications packaged into a single file with <rte-code>apk<rte-code> extension. This makes testing easier as the application can be distributed onto many different testing devices at once.
Unfortunately, this approach has its drawbacks. The overall size of the application is now much bigger than it should be as it contains the files required by all architectures. As a result, users will end up downloading extraneous code that is not even compatible with their phones.
Thankfully, you can optimize the distribution process by taking advantage of App Bundles when releasing a production version of your app.
App Bundle is a publishing format that allows you to contain all compiled code and resources. It’s all due to the fact that Google Play Store Dynamic Delivery will later build tailored APKs depending on end users’ devices.
To build App Bundle, you have to simply invoke a different script than usual. Instead of using <rte-code>./gradlew assembleRelease<rte-code>, use <rte-code>./gradlew bundleRelease<rte-code>, as presented here:
Building a React Native app as App Bundle
The main advantage of Android App Bundle overbuilds for multiple architectures per CPU is the ease of delivery. After all, you have to ship only one artifact and Dynamic Delivery will do the whole magic for you. It also gives you more flexibility on supported platforms. You don’t have to worry about which CPU architecture your end user’s device has. The average size reduction for an app is around 35%, but in some cases, it can be even cut in half, according to the Android team.
Another way of decreasing the build size is by enabling Proguard. Proguard works similarly to dead code elimination from JavaScript - it gets rid of the unused code from third-party SDKs and minifies the codebase.
However, Proguard may not work out-of-the-box with some projects and usually requires additional setup to achieve optimal results. In this example, we were able to reduce the size of the mentioned 28 MB build by 700Kb. It is not much, but it is still an improvement.
Enabling proguard in android/app/build.gradle
Another good practice is keeping your eye on resource optimization. Each application contains some svg or png graphics that can be optimized using free web tools. Reducing redundant text from svg and compressing png images can save some bytes when your project has already a lot of them.
Optimize your app with Gradle for smaller APK and faster TTI
All the steps mentioned above are relatively easy to introduce and worth taking when you’re struggling with a growing application size. You will achieve the most significant size reduction by building the app for different architectures. But the list of possible optimizations doesn’t stop there.
By striving for a smaller APK size, you will do your best to reduce the download cancellation rate. Also, your customers will benefit from a shorter time to interaction and be more inclined to use the app often.
Finally, you will demonstrate that you care about every user, not only those with top-notch devices and fast internet connection. The bigger your platform gets, the more important it is to support those minor groups, as every percentage of users translate into hundreds of thousands of people.
Need help with performance? Give us a shout!
If you’re struggling with improving your app performance, don’t hesitate to contact us. We’re the official Meta and Vercel partners, and we’ve been delivering high-quality solutions for our clients and contributing greatly to the React Native ecosystem for a while. If you’re on the lookout for a performance optimization partner, our React Native development company is surely the right one.