Migrating Native Android App to React Native in 2024

Upgrade your Android app to React Native in 2024 efficiently. This brief guide covers crucial steps and insights for a seamless transition, boosting cross-platform support and streamlining app maintenance. Ideal for developers seeking swift, scalable development solutions.

Migrating Native Android App to React Native in 2024
Photo by Daniel Romero / Unsplash

In my career, I've had to do various refactors and recreate applications, including Mobile, Frontend, and Backend, and I realized that I've never documented this in a post. Recently, I was part of a project where we needed to migrate two native applications (Android in Kotlin and iOS in Swift) to React Native. In addition to migrating all the current features, the idea was to address all the technical debts from the previous versions (conscious debts that were not prioritized) and add new functionalities with a new interface.

I'll take this opportunity to talk about this process, but as an example, I'll use a very simple app that I developed a long time ago, the app in question is the "Front Flashlight Lite" (yes, a flashlight app).
Google sent several alerts about SDK version updates and other policies, and the application even went offline because the terms of use were no longer online.

Overview

The application operates in an extremely simple manner, we can:

  • Turn the device's rear flashlight on and off (if available)
  • Turn the device's front flashlight on and off (if available)

However, all this is done using the device's native camera API, which means I will need to create a native module for this in React Native.

Imagem da captura de tela 3
Versão atual da aplicação

The idea is not only to migrate to React Native but also to create a new interface and new icons to make everything more modern and attractive.

For this migration, we will focus only on Android, and in my planning, I will need to structure in React Native:

  • React Native CLI to start a new project.
  • Configure the Bundle (package name) and use the same Keystore to replace the current app without having to create a new one.
  • Navigation with React Navigation.
  • Styling with Stylesheet (you don't have to use Styled components for everything)
  • React Native Animated (perhaps ReAnimated might deliver better performance)
  • Create a native module to access the camera API and turn on the flash.
  • Firebase library and Admob for analytics and advertisements

Starting

Let's start with the React Navigation part. Here, there's nothing out of the ordinary; we just need to add the libraries to the project and follow the documentation to ensure everything is correct.

yarn add @react-navigation/native react-native-screens react-native-safe-area-context @react-navigation/native-stack

After setting up the route (we have just one), we can now create our folder structure and then start on the UI.

Folder organization

After stylizing the home screen, we get this:

App with animation styles and animation

Native module

Now we need to write the native code, let's create a bridge between React Native and Android. I am writing about this right now and will post as soon as possible.
So, I created the Module and Package classes to control the camera API:

New java files in red

Register the Package in "MainApplication":

Registering the Package

In React Native I created a util to communicate between RN and the Android code:

import { NativeModules } from 'react-native';

export async function turnFlashlight(
  on: boolean,
  camera: 1 | 0,
): Promise<boolean> {
  const { LanternaManager } = NativeModules;

  try {
    return await new Promise((resolve, reject) => {
      LanternaManager.turn(on, camera, (status: boolean) => {
        if (status) {
          resolve(true);
        } else {
          reject(false);
        }
      });
    });
  } catch (e) {
    return false;
  }
}

In the native code, the function has three arguments:

  • status: Turn on (true) or turn off(false) the light.
  • camera: Which flash will be used; frontal (1) or backside (0).
  • callback: Callback to capture the response passed in native code (true or false).

Bundle and sign the application

The most important part of the migration an application is here, all the text above is to illustrate a "real migration case", but when you change your app, because you have to switch the framework, or create a new project from zero and need to replace the old application you need to be careful with two things:

  • Application Id (or Bundle Id)
  • Keystore

This is how the Play Store knows that this application is the same and not a new one (it's a simplified explanation), so, we create a new application and want to replace the old one, let's set up these two points, starting from the application ID changing.
We don't need to change the package name, we need to change the build.gradle and don't need to refactor all the Android application references, folders, etc. It's very simple.

Application ID

Opening the build.gradle from app folder (android/app/build.gradle) we can look for the defaultConfig section. Here we can see the actual application ID.

Android configuration in build.gradle

You can check the actual application ID in the Play Console (or in the old codebase):

The application ID in Play Console

Don't forget to change the version number too, put the current + 1 (or some like that):

KeyStore

Now let's create a new signing config to register or old KeyStore, if you lost this, you can check some solutions to recovery. The React Native documentation covers all these steps very well.
In the same file, scroll to signingConfigs section and create a new entry:

...
android {
    ...
    defaultConfig { ... }
    signingConfigs {
        release {
            if (project.hasProperty('MYAPP_UPLOAD_STORE_FILE')) {
                storeFile file(MYAPP_UPLOAD_STORE_FILE)
                storePassword MYAPP_UPLOAD_STORE_PASSWORD
                keyAlias MYAPP_UPLOAD_KEY_ALIAS
                keyPassword MYAPP_UPLOAD_KEY_PASSWORD
            }
        }
    }
}
...

Now in the buildTypes section, look for release and change the signingConfig to signingConfigs.release to use the newly created configs.

The changed signing config

Edit the gradle.properties in android folder to add the new variables and change the values. Put the same password and alias from the old app and put the .keystore file inside android/app folder.

If your keystore is in jks format it's not a problem, just put the name with extension in the var.
MYAPP_UPLOAD_STORE_FILE=name-of-key-key.keystore
MYAPP_UPLOAD_KEY_ALIAS=my-key-alias
MYAPP_UPLOAD_STORE_PASSWORD=*****
MYAPP_UPLOAD_KEY_PASSWORD=*****

Now build and check:

cd android
./gradlew bundleRelease # Generate .aab

If everything is ok the Google Play Console will accept your new bundle and you are ready to go!

Bonus

Don't forget that if you are writing a new application is a good time to implement things to help you keep the good health of the code. Check these posts to see if this can help you:

React Native UI Kit for 2023
A list of react native ui kit and components libraries to boost your mobile development with beautiful components!
How to Boost Performance in React Applications
React is a powerful library, but as applications become more complex, their performance can suffer. To optimize React application performance, see here some tips.
React Native and Maestro - UI Tests easy
Maestro is a mobile UI testing framework, very simple and effective. It’s an alternative to other frameworks like Appium, Espresso, UIAutomator or XCTest and is built on top of the knowledge from its predecessors. Maestro doesn’t depend on any mobile framework, so you can run it in React Native app…
Optimizing Code Quality in React and React Native with SonarQube Integration
Optimize your React and React Native code quality with SonarQube integration. Explore efficient, scalable, and maintainable coding practices in this insightful guide.
Aumente as Conversões na Black Friday: Estratégia ASO & Ícone Dinâmico no React Native
Foto de CardMapr.nl na Unsplash Bem-vindo ao mundo da Black Friday, a época do ano em que…