Module to expose config variables to your javascript code in React Native, supporting both iOS and Android.
Bring some 12 factor love to your mobile apps!
Forked from luggit's repo
- There was an important issue with the iOS build system that we wanted to fix ASAP back then (but it was merged since)
- Setting environment variables does not work properly in the XCode pre-build phases. This commit helps with setting the environment file in this way. Without this commit, the code below wouldn't work https://github.com/bamlab/react-native-config/commit/38c5f6075d518edd0a53d0c6836e46a828d031c4
echo ".env.staging" > ${SRCROOT}/envfile
ENVFILE=.env.staging ${SRCROOT}/../node_modules/react-native-config/ios/ReactNativeConfig/BuildXCConfig.rb ${SRCROOT}/.. ${SRCROOT}/react-native-config.xcconfig
- We wanted to standardize the way to use the lib
- We wanted control over such a critical lib (it uses env variables)
Install the package:
yarn add @bam.tech/react-native-config
Create a new file .env
in the root of your React Native app:
API_URL=https://myapi.com
GOOGLE_MAPS_API_KEY=abcdefgh
Keep in mind this module doesn't obfuscate or encrypt secrets for packaging, so do not store sensitive keys in .env
. It's basically impossible to prevent users from reverse engineering mobile app secrets, so design your app (and APIs) with that in mind.
You'll also need to manually apply a plugin to your app, from android/app/build.gradle
:
// 2nd line, add a new apply:
apply from: project(':@bam.tech_react-native-config').projectDir.getPath() + "/dotenv.gradle"
In android/app/build.gradle
, if you use applicationIdSuffix
or applicationId
that is different from the package name indicated in AndroidManifest.xml
in <manifest package="...">
tag, for example, to support different build variants:
Add this in android/app/build.gradle
defaultConfig {
...
resValue "string", "build_config_package", "YOUR_PACKAGE_NAME_IN_ANDROIDMANIFEST.XML"
}
When Proguard is enabled (which it is by default for Android release builds), it can rename the BuildConfig
Java class in the minification process and prevent React Native Config from referencing it. To avoid this, add an exception to android/app/proguard-rules.pro
:
-keep class com.mypackage.BuildConfig { *; }
mypackage
should match the package
value in your app/src/main/AndroidManifest.xml
file.
The same environment variable can be used to assemble releases with a different config:
Define a map in build.gradle
associating builds with env files. Do it before the apply from
call, and use build cases in lowercase, like:
(Note: For React Native 0.60 or greater, autolinking is available)
(Note: For Windows, this module supports autolinking when used with react-native-windows@0.63
or later. For earlier versions you need to manually link the module.)
project.ext.envConfigFiles = [
debug: ".env.development",
release: ".env.production",
anothercustombuild: ".env",
]
apply from: project(':@bam.tech_react-native-config').projectDir.getPath() + "/dotenv.gradle"
Also note that besides requiring lowercase, the matching is done with buildFlavor.startsWith
, so a build named debugProd
could match the debug
case, above.
cd ios
pod install
-
Right click on your project folder, create a "New file..."
-
Select the "Configuration Settings File" file type
-
Name it "react-native-config.xcconfig"
-
Remove this file from git (as it will be generated each build):
# .gitignore # react-native-config codegen ios/react-native-config.xcconfig ios/envfile
-
In the Xcode menu, go to Product > Scheme > Edit Scheme
-
Expand the "Build" settings on left
-
Click "Pre-actions", and under the plus sign select "New Run Script Action"
-
Where it says "Type a script or drag a script file", type:
echo ".env.development" > "${SRCROOT}/envfile" ENVFILE=.env.development ${SRCROOT}/../node_modules/@bam.tech/react-native-config/ios/ReactNativeConfig/BuildXCConfig.rb ${SRCROOT}/.. ${SRCROOT}/react-native-config.xcconfig
-
In your xcode project, in the Info tab ...
-
... expand the Configurations section
-
For Debug and Release, on your project name row, select the
react-native-config
configuration option.
The basic idea in iOS is to have one scheme per environment file, so you can easily alternate between them.
For each environment, use the following step (and change development
by your env name - staging, test, production) :
- In the Xcode menu, go to Product > Scheme > Edit Scheme
- Duplicate Scheme
- Expand the "Build" settings on left
- Click "Pre-actions", and under the plus sign select "New Run Script Action"
- Where it says "Type a script or drag a script file", type:
echo ".env.development" > "${SRCROOT}/envfile" ENVFILE=.env.development ${SRCROOT}/../node_modules/@bam.tech/react-native-config/ios/ReactNativeConfig/BuildXCConfig.rb ${SRCROOT}/.. ${SRCROOT}/react-native-config.xcconfig
import Config from "@bam.tech/react-native-config";
Config.API_URL; // 'https://myapi.com'
Config.GOOGLE_MAPS_API_KEY; // 'abcdefgh'
Config variables set in .env
are available to your Java classes via BuildConfig
:
public HttpURLConnection getApiClient() {
URL url = new URL(BuildConfig.API_URL);
// ...
}
You can also read them from your Gradle configuration. All variables are strings, so you may need to cast them. For instance, in Gradle:
defaultConfig {
applicationId project.env.get("APP_ID")
versionCode project.env.get("VERSION_CODE").toInteger()
}
And use them to configure libraries in AndroidManifest.xml
and others:
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="@string/GOOGLE_MAPS_API_KEY" />
Read variables declared in .env
from your Obj-C classes like:
// import header
#import "ReactNativeConfig.h"
// then read individual keys like:
NSString *apiUrl = [ReactNativeConfig envFor:@"API_URL"];
// or just fetch the whole config
NSDictionary *config = [ReactNativeConfig env];
In Info.plist
or project.pbxproj
, read variables like so :
<key>CFBundleDisplayName</key>
<string>$(DISPLAY_NAME)</string>
PROVISIONING_PROFILE_SPECIFIER = "$(PROVISIONING_PROFILE_SPECIFIER)";
For mocking the Config.FOO_BAR
usage, create a mock at __mocks__/@bam.tech/react-native-config.js
.
// __mocks__/react-native-config.js
export default {
FOO_BAR: 'baz',
};
yarn add -D dotenv
// __mocks__/@bam.tech/react-native-config.js
import fs from "fs";
import path from "path";
import dotenv from "dotenv";
const buf = fs.readFileSync(path.resolve(__dirname, "..", "..", ".env"));
const config = dotenv.parse(buf);
export default config;
Forked from original repo created by Pedro Belo at Lugg.