Improve TTI, reduce memory usage and size of your app by adjusting Proguard rules to your projects.

An introduction

The following article is a 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 is important for several reasons. First, not everybody has the luxury of using the latest device and having a stable and fast internet connection. Thus, this group of users may not be able to download and run your big-size apps. It can significantly reduce the number of potential users of your products.

Second, the bigger size, the bigger startup time of the app. It takes much more time to make your product ready for the first interaction with a user when it’s too big. It may seriously harm the user experience of your product.

Third, you need to remember that the app usually takes 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 the previous parts of our guide, we have discussed:

Be sure to check them out.

Now, let’s jump into the main topic.

Issue: You are not enabling Proguard for release builds and creating APK with code for all CPU architectures. You ship larger APK.

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 do 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 next few paragraphs. But first, let’s have a look on 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 have a negative impact on the experience of your end-users. We discuss it in the next section.

Bigger APK size means more time needed to download from app store and more bytecode to load into memory

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 the network accessibility and reliability are far from perfect. Projects such as Loon 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.

diagram of ratio increasing as application size grows

Source: https://segment.com/blog/mobile-app-size-effect-on-downloads/

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 is a relatively big share of mid- to low-end devices that may face issues when dealing with bigger APKs.

diagram of low/mid-level devices in Android market

In March 2019 ONLY 20.8% Android smartphones were high-end, up from 15% in March 2018.

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 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.

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

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: armeabi-v7a, arm64-v8a, x86, and x86_64.

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. 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 ./gradlew assembleRelease, use ./gradlew bundleRelease, 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.

graph presenting how much can gradle reduce the size of the mobile app

Source: https://medium.com/google-developer-experts/exploring-the-android-app-bundle-ca16846fa3d7

Another way of decreasing the build size is by enabling Proguard. Proguard works in a similar way 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 resources 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.

Benefit: Smaller APK, slightly faster TTI, slightly less memory used

All the mentioned steps 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 more 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 percent of users translate into hundreds of thousands of actual users.

Summary

To put everything together, optimizing your Android application’s size positively impacts several important elements of your products. It reduces the download cancellation rate and makes the app more available for every user, regardless of the device performance. Thanks to that, the group of your potential users grows what may result in better ROI of your app.

If you would like to read more about the influence of the app size on downloads, read this article.

Callstack

We are the official Facebook partners on React Native. We’ve been working on React Native projects for over 5 years, delivering high-quality solutions for our clients and contributing greatly to the React Native ecosystem. Our Open Source projects help thousands of developers to cope with their challenges and make their work easier every day.

Contact us if you need help with cross-platform or React Native development. We will be happy to provide a free consultation.