DEV Community

Witalo Benicio
Witalo Benicio

Posted on • Edited on

Smaller and faster React Native apk

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

***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 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 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 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
]
Enter fullscreen mode Exit fullscreen mode

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

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

Top comments (2)

Collapse
 
tombyrer profile image
Tom Byrer

Thanks for the tips!

You can usually get even smaller image sizes by using a tool like Win: FileOptimizer or OSX: ImageOptim. They will use more optimizers after to shrink another 5%, but takes more time. Also, most PNGs look fine if they are 8bit, so there is more savings if you down-sample from 24bit.

Can you give more details about how you shrink your fonts please? I noticed Google's font CDN does this.

Collapse
 
witalobenicio profile image
Witalo Benicio

Nice thoughts on image optimization.

I've used a font from Google. Montserrat.
I had to download all font sizes and put on my app, the problem was that when I've downloaded it, each file was like 400Kb.

That's because they have symbols, chinese chars, and a lot of other chars. Mostly, we use just Latin chars. It's been a while since I did this optimization, but I've used pyftsubset. I just followed the documentation and run a command to delete unnused chars.