Many times when developing an application, we developers need to create different builds with different configurations. Facilitating the maintenance and testing process. Usually 3 different builds are created: development, staging and production.
Install the package
// yarn
yarn add react-native-config
// npm
npm install react-native-config --save
For iOS also run pod install after package is installed
And below line of code to android/app/build.gradle
to apply plugin
apply plugin: "com.android.application"
apply from: project(':react-native-config').projectDir.getPath() + "/dotenv.gradle" // <- add this line
.env.development
ENV=development
API_URL=https://api.dev.com
.env.staging
ENV=staging
API_URL=https://api.staging.com
.env.staging
ENV=production
API_URL=https://api.com
Now we need to define envConfigFiles in build.gradle
associating builds with env files. To achieve this, add the below code before the apply from call, and be sure to leave the build cases in lowercase.
android/app/build.gradle
// add this block
project.ext.envConfigFiles = [
development: ".env.development",
staging: ".env.staging",
production: ".env.production",
]
// ---
apply from: project(':react-native-config').projectDir.getPath() + "/dotenv.gradle"
Adding Product Flavor on project below line compileSdkVersion
android/app/build.gradle
android {
ndkVersion rootProject.ext.ndkVersion
compileSdkVersion rootProject.ext.compileSdkVersion
// add this block
flavorDimensions "default"
productFlavors {
development {}
staging {}
production {}
}
defaultConfig {
applicationId project.env.get("APP_ID") // using env
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 1
versionName "1.0"
buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString()
resValue "string", "build_config_package", "com.saigontechnology.rnbaseprojecttypescript" // add this line
if (isNewArchitectureEnabled()) {
// We configure the CMake build only if you decide to opt-in for the New Architecture.
externalNativeBuild {
cmake {
arguments "-DPROJECT_BUILD_DIR=$buildDir",
"-DREACT_ANDROID_DIR=$rootDir/../node_modules/react-native/ReactAndroid",
"-DREACT_ANDROID_BUILD_DIR=$rootDir/../node_modules/react-native/ReactAndroid/build",
"-DNODE_MODULES_DIR=$rootDir/../node_modules",
"-DANDROID_STL=c++_shared"
}
}
if (!enableSeparateBuildPerCPUArchitecture) {
ndk {
abiFilters (*reactNativeArchitectures())
}
}
}
}
// ---
...
Value APP_ID
in env below:
API_URL=
APP_ENV=dev
CODEPUSH_KEY_IOS=
CODEPUSH_KEY_ANDROID=
APP_ID=com.saigontechnology.rnbaseprojecttypescript.development // this line
APP_NAME=BaseDev
Names should match based on productFlavors, so productiondebug will match debug in this case and generate debug build of App with configuration from .env.production
.
Also add matchingFallbacks in buildTypes as shown below:
android/app/build.gradle
buildTypes {
debug {
signingConfig signingConfigs.debug
matchingFallbacks = ['debug', 'release'] // <- add this line
}
release {
signingConfig signingConfigs.debug
minifyEnabled enableProguardInReleaseBuilds
proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
}
}
Edit file android/app/src/main/res/values/string.xml
.
- Change
app_name
using env:
<resources>
<string name="app_name">@string/APP_NAME</string>
<string moduleConfig="true" name="CodePushDeploymentKey">@string/CODEPUSH_KEY_ANDROID</string>
</resources>
- Value
APP_NAME
andCODEPUSH_KEY_ANDROID
in file env
API_URL=
APP_ENV=dev
CODEPUSH_KEY_IOS=
CODEPUSH_KEY_ANDROID=
APP_ID=com.saigontechnology.rnbaseprojecttypescript.development
APP_NAME=BaseDev // this line
- The result should be like
Create bash script run android run-app.bash
in folder scripts
prompt_android="Please select variant for android: "
OPTIONS_ANDROID=(
"developmentDebug"
"developmentRelease"
"stagingDebug"
"stagingRelease"
"productionDebug"
"productionRelease"
"quit"
)
if [ "$1" == "android" ]
then
PS3="$prompt_android"
select opt in "${OPTIONS_ANDROID[@]}"; do
if [ "$opt" == "quit" ]
then
break
fi
if [ "$opt" == "" ]
then
echo "Invalid"
else
echo "Variant: $opt"
npx react-native run-android --variant=$opt
break
fi
done
fi
If you choose different environment base on "Active Build Variant" from "Android Studio" you may need additional configuration
productFlavors {
development {
applicationId ${Your Development Id}
resValue "string", "build_config_package", "com.saigontechnology.rnbaseprojecttypescript"
}
staging {
applicationId ${Your Staging Id}
resValue "string", "build_config_package", "com.saigontechnology.rnbaseprojecttypescript"
}
production {
applicationId ${Your Production Id}
resValue "string", "build_config_package", "com.saigontechnology.rnbaseprojecttypescript"
}
}
When you create a new project, Xcode automatically generates two types of schemes for you, and they are Debug and Release.
The above approach still shows debug, but in reality, it's actually a staging according to its condition change. The clean approach is to create a new scheme.
You could easily duplicate on top of debug or release. Usually, it’s on top of debug as you don't really need an additional release.
Once you have duplicated on top of debug, you may then rename it to staging.
The next step is to make it so we can run these apps side-by-side.
On the top bar, click the + sign and “Add User-Defined Setting”
Name it BUNDLE_ID_SUFFIX (or something similar — you’ll need to re-use this name later)
Open the dropdown and give the following values for each configuration, leaving the “Release” value blank:
While you’re in your project settings, select your Target from the left sidebar and go to the “Build Settings” tab and search product name. Edit value Base$(BUNDLE_ID_SUFFIX)
While you’re in your project settings, select your Target from the left sidebar and go to the “Build Settings” tab and search product bundle
Lastly, a final touch would be to add different app icons based on the scheme. You will have to add the icon to the AppIcon.
Next, you can duplicate the AppIcon and rename it, as shown below:
Inside the project, you will then use different AppIcon based on the scheme.
You can duplicate scheme and edit it, as show below:
Edit schema > Build > Pre-actions
Select schema build settings same as selected schema and add this script
RNBaseProjectDev
cp "${PROJECT_DIR}/../.env.development" "${PROJECT_DIR}/../.env"
RNBaseProjectStg
cp "${PROJECT_DIR}/../.env.staging" "${PROJECT_DIR}/../.env"
RNBaseProject
cp "${PROJECT_DIR}/../.env.production" "${PROJECT_DIR}/../.env"
Create bash script run ios run-app.bash
in folder scripts
prompt_ios="Please select variant for ios: "
OPTIONS_IOS=(
"RNBaseProjectDev"
"RNBaseProjectStg"
"RNBaseProject"
"quit"
)
if [ "$1" == "ios" ]
then
PS3="$prompt_ios"
select opt in "${OPTIONS_IOS[@]}"; do
if [ "$opt" == "quit" ]
then
break
fi
if [ "$opt" == "" ]
then
echo "Invalid"
else
echo "Scheme: $opt"
npx react-native run-ios --scheme "$opt"
break
fi
done
fi
How To Set Different App Icons and Name Using Xcode Scheme
React Native: Multiple Environments Setup (Schemas/Flavors)
Different App Icons for your iOS Beta, Dev, and Release builds
If you have any feedback, please reach out to us at loi.do@saigontechnogoly.com
For support, email loi.do@saigontechnogoly.com or join our Slack channel.