loading...

Smaller and faster React Native apk

witalobenicio profile image Witalo Benicio ・6 min read

With simple (or not) steps

Hi, everyone

As you may know, Android devices are very different from each other, varying on storage, RAM size, CPU power and so on. Based on that, we (as developers) always need to focus on a better performance of our application, so it will work well in a low-end and high-end device.

I work at a Brazilian Fintech called MEU TUDO. We offer a digital way to get a payroll loans from multiple banks.
From MEU TUDO point of view, we need to be even more carefully about low-end devices, since our application is most used on those devices.

And this is not only about how good will be the experience to the final user, it directly impacts on the decision to download the app or not.

Let's take a look at our size before the improvement:

Our application was more than 8Mb bigger than the peers

Our application was more than 8Mb bigger than the peers

And after we improve:

We got a 11Mb reduction compared to peers

We got a 11Mb reduction compared to peers

Alt Text
Alt Text

We went from 45Mb to 25Mb

Ok...but how we can reduce our apk size?

Newest React Native version

The very first thing to do is to upgrade your application to a recent version of React Native, at least 0.60.4.
Why?
Because they have introduced very interesting features like Hermes (that I'll talk about later on this article), autolink (which doesn't directly impact on size but impacts in faster integrations), for iOS the default way to get libs is with CocoaPods (which is very helpful), and so on.

Considering MEU TUDO application it was easier for our case creating a new project and migrate our code to the new project than trying to upgrade our actual project. So I've just created a fresh new React Native project, and started to add new versions of libs that we use, while trying to run them separately (to ensure that wouldn't crash after adding a bunch of them, and we would get lost), and after that, migrate all the code.

App Bundle

This is really not such a new feature, but it has a big impact on the apk size.
App Bundle is a new and recommended way of generate and distribute your application.

AAB will contain all of your compiled code and resources, and you will only need to upload it to Google Play. After that, PlayStore will handle it and generate an optimized and specific apk for each device. This way, your application will only have the essential for that specific device, and will deliver a much smaller apk. As you saw in above picture, MEU TUDO apk vary from 16Mb to 26Mb, depending on device.

To generate your app bundle, you can simple change your ./gradlew assembleRelease to ./gradlew bundleRelease. It will generate an .aab file that you will send to Play Store.

Hermes

Hermes is a JavaScript engine optimiser for React Native developed from Facebook. It will provide a smaller bundle and a faster launch.
Newer versions of React Native already are integrated with Hermes, which makes really easy to use.

To start using Hermes you just need to change the following code to true in android/app/build.gradle:

project.ext.react = [
    enableHermes: true,  // clean and rebuild if changing
]

But be careful, if you are using react-native-webview with injectedJavaScriptprop and converting your injected function withString(myFunction)ormyFunction.toString(), it will not work, because Hermes will ignore thetoString()` part and transform your function to bytecode that then will be converted to String and will end-up not working. So if you use this way, you will have to explicitly pass a String as function.`

Assets optimization

If you ever stopped to look at your assets you may have notice that, together, they are big, really big, most of time. You put an 120Kb image and thinks "This is not so big", and you put another, and another, and you end-up with some Mbs only from images.

But not only images are a problem. Fonts too.
Your designer thinks in this beautiful design, with this cool font and when you saw it, just the fonts are like 1.5Mb.

To just not assume that you images and fonts are big, you can use the Android Size Analyzer to know exactly which files are bigger.
You just need to run size-analyzer check-bundle -d [BUNDLE].aab in your previous generated .aab file and get the list with large files and suggestions.

And one of the suggestions may be to enable...

Proguard

A tool to shrink, obfuscate, and optimize your Java bytecode.
To start using proguard in your releases, just change to true the following line in android/app/build.gradle.

def enableProguardInReleaseBuilds = true

Bear in mind that some libs require to add some "code" to proguard to keep working

Large images

Ok... you run the size-analyzer check-bundle command and got a list of images and other files.
But what to do with images?
Here is a simple "trick". You can use TinyPNG to reduce your images sizes by almost 50-70%.

Fonts

That can be a problem depending on the font you use and if you use all the weights. And this can be a problem due to the fact that some fonts have lots of special characters that you will never use, or maybe languages that you will never use.

To improve your fonts size you can use some tools to remove all non ISO-8859-15 (Latin0) characters.
Tools like:

Or any other tool that you may find.

After removing those unused chars you can get a reduction of 80-90% of the font size! That's really awesome!

Bundle analyzer

During the development of an application you always at some moment will try some libs to solve a problem, or you may use a lib to solve a problem that later you may not need anymore, or even using a lib for simple things that doesn't require a lib to.

To analyze a bundle and see what is taking up the space, we can use react-native-bundle-visualizer.
Running it on your project, will give an image that looks like the following one:

Example of bundle analyzer

From that you can get a visualization of every folder of the application, and analyze which one is costing you more.

From MEU TUDO project, I've checked that lodash and aws-pinpoint/aws-sdk were the main libs to work on.
I started looking at the project the places where I used lodash and, for my surprise (or not), I was using in only ONE place. To solve this, I removed lodash, and implemented the method myself because it was a really simple method.
After that, I started to look for a solution for aws libs. Initially we were using them as a single package, and this comes with problems, because we had all the packages together, but we were only using one of them. So I searched for a most recent version of the libs, and notice that they already had separated projects as @aws/core and @aws/analytics.

This is one of the examples that can be improved, but this is really relative to individual projects, and you will have to analyze your specific cases.

Thats it

With those steps, we were able to reduce our .apk size from 45Mb to 16-25Mb, with really fast load, and a better performance and feel in use.

When working in fast growing startup as MEU TUDO, we always focus on the client and business needs, and sometimes this impacts on the accumulation of technical debts so the product can grow faster. At the beginning this can be put aside, but as soon as the company starts to increase his numbers of users and interactions, you need to start paying those debts.

Posted on by:

witalobenicio profile

Witalo Benicio

@witalobenicio

Frontend Developer with an eye for design.

Discussion

markdown guide