Making environment based apks for a react native application for android
Tags: reactnative, android, javascript, tutorial
Published: 2022-04-04 06:52:34

An Android device identifies each application with its associated package name, and normally would only allow single instance of an application to be installed at a time. 
So if a device has an application installed with a package name `com.org.weatherapp`, it will be the only instance installed at a time, and any application with the same package name would update the existing installation.

So what if we have to allow our teams to be able to install multiple copies of our application. 

Like if a tester has a production release installed in his device and he has to test a new feature on development environment, it would be awful if had to uninstall the production copy to install a development apk that he would only use temporarily. 

_That doesn't sound like something that happens in reality?_

Well you're right, it doesn't.

Let me show you how we can create different apks for different environments in react-native, that will allow all of them to be installed simultaneously on any device!
Not only that but we are also going to use different application launcher icons, so it is easier to differentiate between different copies.

We will start by using a different package name for each copy of our application

```
com.org.weatherapp.test // For test environment
com.org.weatherapp.dev  // For dev environement
com.org.weatherapp // For production environment
```

I'm using three different package names, but it will work for any number of environments as you might need. Just keep in mind, every copy must have a unique package name or else it override the existing installation.

### 1. Create assets for each environment

Open Android Studio and change the left side menu to `Android`, right click on the assets folder and click on `New -> Image Asset`.
Configure the name and any other properties you like and click on `Finish`.

Repeat for each environment, and name them accordingly.

```
ic_test_launcher.png // For test environment
ic_dev_launcher.png  // For dev environement
ic_launcher.png // For production environment
```

Android Studio will create all variations of assets and put them in mipmap and drawable folders.

### 2. Use different icons for each environment

Now we need to tell our application to use different launcher icons on each environment.

Open `android/app/src/main/AndroidManifest.xml` and change the following lines:

```xml
    <application
        android:name=".MainApplication"
        android:allowBackup="false"
        android:label="@string/app_name"
---     android:icon="@mipmap/ic_launcher"
---     android:roundIcon="@mipmap/ic_launcher_round"
+++     android:icon="${appIcon}"
+++     android:roundIcon="${appIconRound}"
        android:theme="@style/AppTheme">
        ...
        ...
    </application>
```

We use placeholders for app launcher icons. Which we will define in the next step.

#### 3. Define different application flavors

We have to define different application flavors.
Open `android/app/build.gradle` and add the following lines:

```gradle
    android {
        ...
        defaultConfig {
            ...
        }
        flavorDimensions "version"
        productFlavors {
            test {
                applicationIdSuffix ".test"
                manifestPlaceholders = [
                    appIcon: "@mipmap/ic_test_launcher",
                    appIconRound: "@mipmap/ic_test_launcher_round"
                ]
            }
            dev {
                applicationIdSuffix ".dev"
                manifestPlaceholders = [
                    appIcon: "@mipmap/ic_dev_launcher",
                    appIconRound: "@mipmap/ic_dev_launcher_round"
                ]
            }
            production {
                manifestPlaceholders = [
                    appIcon: "@mipmap/ic_launcher",
                    appIconRound: "@mipmap/ic_launcher_round"
                ]
            }
        }
    }
```

So what we did here?
1. We defined three product flavors for our application, test, dev, and production. 
2. applicationIdSuffix is a property that will be used to append the package name to the application id. So test apk will have the package name `com.org.weatherapp.test` and dev apk will have the package name `com.org.weatherapp.dev`. We didn't define applicationIdSuffix for production because we don't want to append anything to it.
3. manifestPlaceholders are the variables we defined earlier in `AndroidManifest.xml` they will be used to replace the placeholders in the manifest file. This will allow us to use different icons for each environment.

### 4. Updating build scripts

We have to update our build scripts that will be used to create different flavored apks.

Open `package.json` and add the following lines:

```json
"scripts": {
    "bundle": "react-native bundle --platform android --dev false --entry-file index.js --bundle-output android/app/src/main/assets/index.android.bundle --assets-dest",
    "android": "react-native run-android --variant testDebug --appId com.org.weatherapp.test",
    "dev-apk": "yarn bundle && cd android && ./gradlew assembledevDebug",
    "prod-apk": "yarn bundle && cd android && ./gradlew assembleproductionDebug"
}
```

1. bundle is the command that will be used to create the index.bundle file.
2. We update android script to use the testDebug variant of the application.
3. We use dev-apk script to use the devDebug variant of the application.
4. Same for production, ofcourse production build will be a release variant instead of debug, but that is a different process out of scope of this tutorial.

That's It!
Now you can install all flavors of your application on any device at the same time.

If you found this guide useful, leave a like. If you have any questions or feedback, drop it below. Thanks :thumbsup: