Smaller and faster React Native apk
Tags: reactnative, android, apk, react
Published: 2020-07-24 12:36:23

##With simple (or not) steps

###Hi, everyone

As you may know, Android devices are very different from each other, varying in 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 on a low-end and high-end device.

I work at a Brazilian Fintech called [MEU TUDO](https://meutudo.com.br). We offer a digital way to get payroll loans from multiple banks.
From meutudo's point of view, we need to be even more careful about low-end devices, since our application is most used on those devices.

This is not only about how good the experience will be to the final user; it directly impacts 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](https://dev-to-uploads.s3.amazonaws.com/i/0isp7r8ieqtgrtuyxm1e.png "Our application was more than 8Mb bigger than the peers")
<center>***Our application was more than 8Mb bigger than the peers***</center>

And after we improve:

![We got a 11Mb reduction compared to peers](https://dev-to-uploads.s3.amazonaws.com/i/ww5mg82epdykhiwa3dzw.png)
<center>***We got a 11Mb reduction compared to peers***</center>


![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/t2hzqxlvf4j3w7oddi81.png)
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/bxbpmi8ccnv821on78re.png)

<center>***We went from 45Mb to 25Mb***</center>


###**Ok...but how can we reduce our APK size?**

##**Newest React Native version**

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

Considering the meutudo application, it was easier for our case to create a new project and migrate our code to the new project than trying to upgrade our actual project. So I've just made 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 not such a new feature, but it greatly impacts the apk size.
[App Bundle](https://developer.android.com/guide/app-bundle) is a new and recommended way of generating and distributing your application.

AAB will contain all your compiled code and resources, and you 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 essentials for that specific device and will deliver a much smaller app. As you saw in the above picture, the meutudo APK varies from 16Mb to 26Mb, depending on the device.

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

##**Hermes**

[Hermes](https://hermesengine.dev) is a JavaScript engine optimiser for React Native developed by Facebook. It will provide a smaller bundle and a faster launch.
Newer versions of React Native are already integrated with Hermes, which makes it 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 injectedJavaScript` prop and converting your injected function with `String(myFunction)` or `myFunction.toString()`, it will not work, because Hermes will ignore the `toString()` 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 noticed that, together, they are big, really big, most of the time. You put a 120Kb image and think, "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 your images and fonts are big, you can use the [Android Size Analyzer](https://developer.android.com/topic/performance/reduce-apk-size#size-analyzer) to know exactly which files are bigger.
You just need to run `size-analyzer check-bundle -d [BUNDLE].aab` in your previously 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](https://tinypng.com) to reduce your images sizes by almost 50-70%.

##**Fonts**

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

To improve your font size, you can use some tools to remove all non ISO-8859-15 (Latin0) characters.
Tools like:
- [FontForge](https://fontforge.org/en-US/)
- [FontTools](https://github.com/fonttools/fonttools) with `pyftsubset`

Or any other tool that you may find.

After removing those unused chars, you can reduce 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 use a lib for simple things that don't require a lib to.

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

![Example of bundle analyzer](https://dev-to-uploads.s3.amazonaws.com/i/fz4zdbprfoy4zhpaw3v8.png)

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

From meutudo 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 a fast-growing startup such as meutudo, we always focus on the client and business needs, and sometimes this impacts 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 its number of users and interactions, you need to start paying those debts.