How Kargo create their first React Native App

Giovanka Bisano
Kargo Technologies
Published in
8 min readOct 13, 2022
Photo by William Hook on Unsplash

Since Kargo has established 3 years ago, Kargo has had tremendous evolution. From tech stack — to our business process, especially in the Logistics industry which has a very dynamic process and our job is to provide our customers with the solutions necessary and bring the product solution to market. Moreover, every customer has different characteristics, and requirements and sometimes we need to productize our proposed solution for them.

When we talk about the logistics industry, of course, we will think about a Shipper as an actor who wants to send their items. For small and medium Shippers, usually rely on a salesperson from their logistics partner to arrange their delivery.

In Kargo, we assign our salesperson to some shippers. It results in one salesperson needing to handle multiple shipments every day and everything was done manually. Of course; it is tiring. There was a time when some other engineers and I went to empathy research and follow our salesperson for one day to understand their work process. From that one-day session, we found lots of insight and the main takeaway is; a salesperson needs 25–30 minutes to create one delivery order. That’s one main reason why we need to digitalize their process! We believe it might help their work be more time efficient.

Delivery order is a document / request which orders the release of the transportation of cargo to another party.

A Little Bit Journey of Kargo Mobile App

Native, and always Native

Kargo had 3 mobile app products, and everything was built with an android native codebase. There’s nothing wrong with native code, and we are pretty happy about it. But we definitely need to try something new if we have the right use cases in order to expand our knowledge.

Until now, all of our salespersons use Android devices, but it doesn’t close the possibility if we would have a salesperson that uses iOS in the future. We also don’t have hundreds of salespeople, so it doesn’t make sense if we need to create 2 native codebases for Android and iOS.

For that reason, we decide to use a cross-platform codebase. We have 2 options, either Flutter or React Native. That was a tough choice. Long story short, we choose React Native with some consideration

  1. Fast Refresh = Fast coding
    Since RN v0.61, a new feature was introduced. It is called fast refresh which unifies live and hot reloading. It’s more resilient to typos and mistakes compared to the previous version. You can read more about fast refresh here.
  2. One codebase for 2 mobile platforms
    Exactly the same as Flutter; write a single codebase for 2 apps covering both Android and iOS platforms.
  3. Give developer freedom!
    In an app, we need to think about navigation, handling the global states, and a lot more. RN let the developer decide whether they’d prefer to use a custom UI library, or write their own.
  4. Javascript. The popular kid in the school…
    RN uses Javascript, a programming language that many developers are familiar with. Meanwhile, Flutter uses Dart, and that is still not so widely known or used (at least until this article was written).
    In our engineering team, we don’t have people that have expertise in Dart, meanwhile, we have plenty of frontend engineers that familiar with React framework and Javascript.
  5. Maturity
    React native was released in 2015 compared to Flutter released in 2017. The Facebook team has had plenty of time to stabilize the API, as well as focus on fixing issues and solving problems.
  6. App size
    Face it, size matters.
    Flutter has a slightly bigger app size, you can check the article below. With the same “Hello World” app, Flutter takes more storage mainly because Flutter’s C/C++ engine and Dart VM get way too bulky.
    Meanwhile, in Kargo, we need to make our app size as small as possible, because our users might not use the best high-end flagship phone. Also based on Google research, a higher APK size resulting a lower install conversion rate.

Initiation!

Before we start writing code, we surely need to know the product vision first! We want to create a product for helping our salesperson to manage their delivery order. It surely involves basic functions like CRUD to our backend. We worked closely with the Product team to understand the long-term vision, goal, and features of this app. Why do we need to do that? Simple, we need to research and prepare on what tech stack/library we gonna use.

With good product understanding, we also make pretty good decisions. We realize that we have similar products that are written in React JS (web), and that existing web products also have similar capabilities to the upcoming app that we gonna create (create delivery orders, see delivery orders, choose a list of trucks, etc). Yes, monorepo can help us!

Monorepo resulting faster code development because our new app has similar functionality to our existing product, which means we are able to reuse existing code. We just need to put every common function in core directory, make them as components, then both of our products just call that component/function inside core.

Migrating to Monorepo

Because we want to implement this new app with monorepo, we surely need to add a parent folder from the existing product. It sounds simple but actually chaotic.

  1. Create a new folder on top of the current root folder, then move the .git file to into the “new root”
  2. Create new package.json In the root folder to point out that our project is actually in another folder (inside packages folder)
  3. Create react native app inside packages folder (npx react-native init salesApp). It will generate us a basic react native project.

Our monorepo setup is done! But we still couldn’t run our app, there’s one more thing left! We need to fix the location of our entryFile and root that already defined in build.gradle(app). We need to tell android that our react library is placed in the root of the monorepo project, not in the react native project.

It’s all set! Now we are able to run our app in the mono repository.

Now we just need to install our desired libraries such as moment / lodash / react-navigation / anything that you gonna use. There is no fancy syntax to install the library, just use the usual yarn command. We can install our libraries by opening our react native folder and execute yarn add [library name]

Environment Creation

It’s a common practice that we have different environments for a product. In Kargo, we have Dev, Staging, and Production. We need to make 3 of those environments and each of that env will have a different environment variable. Just add your desired environment name inside productFlavors in app/build.gradle.

After we create and configure product flavors, we just need to sync the gradle file (using ./gradlew clean), then Gradle automatically creates build variants based on build types and product flavors. The build variants will have a combination of names of <product-flavor><Build-Type>. For example, in our case, Gradle creates the following build variants:

  • devDebug
  • devRelease
  • stagingDebug
  • stagingRelease
  • prodDebug
  • prodRelease

After defining build variants, we need to modify our scripts in package.json so that it matches our app variants to run the app.

With the script changed, we can run our app and able to choose the build variant easily. For example, to run a Dev Debug version, we just open our terminal and execute yarn run dev-debug.

SVG Library

We definitely need icons inside our app, and we need a library that is able to help us on showing and manage icons because we’ll have various icons on every page. Nowadays, the mobile app doesn’t use images as an icon, we use SVG.

SVG has replaced JPEG / PNG for showing icons. SVG is vector based and has a smaller size. Those are the main benefits of using SVG in the mobile app. We are able to make sure that our icons have good resolution quality (because vectors will have the same quality and smoothness regardless of the phone screen size) and that our app will not take up too much space.

If we use a raster image type (ie: JPEG / PNG), we need to provide 5 different image sizes such as mdpi, hdpi, xhdpi, xxhdpi, xxxhdpi. That makes our app size become massive and it also gives our designer lots of work which may result in we can’t move fast!

We use react-native-vector-icons for our icons. It is also perfect for buttons, logos, and nav/tab bars. Easy to extend, style, and integrate into our project.

It has lots of icon bundles such as AntDesign, FontAwesome, MaterialIcons, etc. But be cautious, when we install this library into our project, it will download lots of icon bundles as I mentioned earlier. Pick one wisely!

The engineering team needs to work closely with the product design team to choose which icon bundles they gonna use. Because by using this library, we “force” the designer to use pre-built icon design from that bundle. And one more thing, we need to choose one .ttf file/bundle if we can, so that we can delete any others that we won’t use to make our app size smaller. In Kargo, we choose MaterialCommunityIcons the bundle because the icons have similar characteristic as our design style and it have the most icons (5346 icons) compared to other bundle.

You can find list of icons from each bundle in this website https://oblador.github.io/react-native-vector-icons/

With that installed, everytime we need to show an icon, we only need to find the icon name and type a one liner code like this.
<Icon name="bell-outline" size={20} />

And then what?

Everything is set! We have successfully created our first react native project, we use the necessary libraries for our development, then we are good to code!

Our impressions of our first react native app are; it makes us able to code faster which may result in the faster product going to market and business skyrocketing. React Native has high code-reusability because it is a component-based project. And it also has a Hot-Reloading feature that makes our code changes become live immediately without needing to recompile our app.

But despite that great advantages, it is difficult to create a complex function that requires background services like Alarm Service, or interactive MapView that we can do easily in a Native framework.

If we want to create a very simple app that solves simple business problems, React Native is the way to go. But if we want to create a complex app that solves big business problems and requires high performance due to lots of heavy logic, I still prefer the Native solution.

Back to the main problem, this Kargo’s first react native apps have successfully helped our sales person on managing delivery orders. Previously, a salesperson needs 25–30 minutes to create a delivery order. But now with this app, they are able to create a delivery order in under 3 minutes. A big win for us!

--

--

Giovanka Bisano
Kargo Technologies

Technical Lead at Kargo Technologies | Google Associate Android Developer Certified