Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Setting environment variable in react-native?

I am using react-native to build a cross-platform app, but I do not know how to set the environment variable so that I can have different constants for different environments.

Example:

development: 
  BASE_URL: '',
  API_KEY: '',
staging: 
  BASE_URL: '',
  API_KEY: '',
production:
  BASE_URL: '',
  API_KEY: '',
like image 797
Damon Yuan Avatar asked Oct 14 '15 05:10

Damon Yuan


People also ask

How do I manage environment variables in React Native?

All you have to do is write or define your variable in your root folder. Then, you can import the variable in your component before calling it. While env variables are very useful in React Native, it is not advisable to use them to store sensitive information like API keys, authentication keys, or passwords.

What is environment variable in React Native?

An environment variable is a variable who's value is set from outside the program. This variable is made up of a key/value pair that can be accessed simply by importing the variable from source file of your React Native App. In some cases, such as in React, the variable doesn't need to be imported at all.


10 Answers

Instead of hard-coding your app constants and doing a switch on the environment (I'll explain how to do that in a moment), I suggest using the twelve factor suggestion of having your build process define your BASE_URL and your API_KEY.

To answer how to expose your environment to react-native, I suggest using Babel's babel-plugin-transform-inline-environment-variables.

To get this working you need to download the plugin and then you will need to setup a .babelrc and it should look something like this:

{
  "presets": ["react-native"],
  "plugins": [
    "transform-inline-environment-variables"
  ]
}

And so if you transpile your react-native code by running API_KEY=my-app-id react-native bundle (or start, run-ios, or run-android) then all you have to do is have your code look like this:

const apiKey = process.env['API_KEY'];

And then Babel will replace that with:

const apiKey = 'my-app-id';
like image 183
chapinkapa Avatar answered Oct 03 '22 18:10

chapinkapa


In my opinion the best option is to use react-native-config. It supports 12 factor.

I found this package extremely useful. You can set multiple environments, e.g. development, staging, production.

In case of Android, variables are available also in Java classes, gradle, AndroidManifest.xml etc. In case of iOS, variables are available also in Obj-C classes, Info.plist.

You just create files like

  • .env.development
  • .env.staging
  • .env.production

You fill these files with key, values like

API_URL=https://myapi.com
GOOGLE_MAPS_API_KEY=abcdefgh

and then just use it:

import Config from 'react-native-config'

Config.API_URL  // 'https://myapi.com'
Config.GOOGLE_MAPS_API_KEY  // 'abcdefgh'

If you want to use different environments, you basically set ENVFILE variable like this:

ENVFILE=.env.staging react-native run-android

or for assembling app for production (android in my case):

cd android && ENVFILE=.env.production ./gradlew assembleRelease
like image 40
Patrik Prevuznak Avatar answered Oct 03 '22 18:10

Patrik Prevuznak


The simplest (not the best or ideal) solution I found was to use react-native-dotenv. You simply add the "react-native-dotenv" preset to your .babelrc file at the project root like so:

{
  "presets": ["react-native", "react-native-dotenv"]
}

Create a .env file and add properties:

echo "SOMETHING=anything" > .env

Then in your project (JS):

import { SOMETHING } from 'react-native-dotenv'
console.log(SOMETHING) // "anything"
like image 29
Slavo Vojacek Avatar answered Oct 03 '22 17:10

Slavo Vojacek


React native does not have the concept of global variables. It enforces modular scope strictly, in order to promote component modularity and reusability.

Sometimes, though, you need components to be aware of their environment. In this case it's very simple to define an Environment module which components can then call to get environment variables, for example:

environment.js

var _Environments = {
    production:  {BASE_URL: '', API_KEY: ''},
    staging:     {BASE_URL: '', API_KEY: ''},
    development: {BASE_URL: '', API_KEY: ''},
}

function getEnvironment() {
    // Insert logic here to get the current platform (e.g. staging, production, etc)
    var platform = getPlatform()

    // ...now return the correct environment
    return _Environments[platform]
}

var Environment = getEnvironment()
module.exports = Environment

my-component.js

var Environment = require('./environment.js')

...somewhere in your code...
var url = Environment.BASE_URL

This creates a singleton environment which can be accessed from anywhere inside the scope of your app. You have to explicitly require(...) the module from any components that use Environment variables, but that is a good thing.

like image 31
tohster Avatar answered Oct 03 '22 17:10

tohster


I used the __DEV__ polyfill that is built into react-native in order to solve this problem. It is automatically set to true so long as you are not building react native for production.

E.g.:

//vars.js

let url, publicKey;
if (__DEV__) {
  url = ...
  publicKey = ...
} else {
  url = ...
  publicKey = ...
}

export {url, publicKey}

Then just import {url} from '../vars'and you'll always get the correct one. Unfortunately, this wont work if you want more than two environments, but its easy and doesn't involve adding more dependencies to your project.

like image 35
Logister Avatar answered Oct 03 '22 18:10

Logister


i have created a pre build script for the same problem because i need some differents api endpoints for the differents environments

const fs = require('fs')

let endPoint

if (process.env.MY_ENV === 'dev') {
  endPoint = 'http://my-api-dev/api/v1'
} else if (process.env.MY_ENV === 'test') {
  endPoint = 'http://127.0.0.1:7001'
} else {
  endPoint = 'http://my-api-pro/api/v1'
}

let template = `
export default {
  API_URL: '${endPoint}',
  DEVICE_FINGERPRINT: Math.random().toString(36).slice(2)
}
`

fs.writeFile('./src/constants/config.js', template, function (err) {
  if (err) {
    return console.log(err)
  }

  console.log('Configuration file has generated')
})

And i have created a custom npm run scripts to execute react-native run..

My package-json

"scripts": {
    "start-ios": "node config-generator.js && react-native run-ios",
    "build-ios": "node config-generator.js && react-native run-ios --configuration Release",
    "start-android": "node config-generator.js && react-native run-android",
    "build-android": "node config-generator.js && cd android/ && ./gradlew assembleRelease",
    ...
}

Then in my services components simply import the auto generated file:

import config from '../constants/config'

fetch(`${config.API_URL}/login`, params)
like image 24
Toni Chaz Avatar answered Oct 03 '22 18:10

Toni Chaz


The specific method used to set environment variables will vary by CI service, build approach, platform and tools you're using.

If you're using Buddybuild for CI to build an app and manage environment variables, and you need access to config from JS, create a env.js.example with keys (with empty string values) for check-in to source control, and use Buddybuild to produce an env.js file at build time in the post-clone step, hiding the file contents from the build logs, like so:

#!/usr/bin/env bash

ENVJS_FILE="$BUDDYBUILD_WORKSPACE/env.js"

# Echo what's happening to the build logs
echo Creating environment config file

# Create `env.js` file in project root
touch $ENVJS_FILE

# Write environment config to file, hiding from build logs
tee $ENVJS_FILE > /dev/null <<EOF
module.exports = {
  AUTH0_CLIENT_ID: '$AUTH0_CLIENT_ID',
  AUTH0_DOMAIN: '$AUTH0_DOMAIN'
}
EOF

Tip: Don't forget to add env.js to .gitignore so config and secrets aren't checked into source control accidentally during development.

You can then manage how the file gets written using the Buddybuild variables like BUDDYBUILD_VARIANTS, for instance, to gain greater control over how your config is produced at build time.

like image 37
vhs Avatar answered Oct 03 '22 17:10

vhs


I use babel-plugin-transform-inline-environment-variables.

What I did was put a configuration files within S3 with my different environments.

s3://example-bucket/dev-env.sh
s3://example-bucket/prod-env.sh
s3://example-bucket/stage-env.sh

EACH env file:

FIRSTENV=FIRSTVALUE
SECONDENV=SECONDVALUE

Afterwards, I added a new script in my package.json that runs a script for bundling

if [ "$ENV" == "production" ]
then
  eval $(aws s3 cp s3://example-bucket/prod-env.sh - | sed 's/^/export /')
elif [ "$ENV" == "staging" ]
then
  eval $(aws s3 cp s3://example-bucket/stage-env.sh - | sed 's/^/export /')
else
  eval $(aws s3 cp s3://example-bucket/development-env.sh - | sed 's/^/export /')
fi

react-native start

Within your app you will probably have a config file that has:

const FIRSTENV = process.env['FIRSTENV']
const SECONDENV = process.env['SECONDENV']

which will be replaced by babel to:

const FIRSTENV = 'FIRSTVALUE'
const SECONDENV = 'SECONDVALUE'

REMEMBER you have to use process.env['STRING'] NOT process.env.STRING or it won't convert properly.

like image 4
Jack Zhang Avatar answered Oct 03 '22 19:10

Jack Zhang


I think something like the following library could help you out to solve the missing bit of the puzzle, the getPlatform() function.

https://github.com/joeferraro/react-native-env

const EnvironmentManager = require('react-native-env');

// read an environment variable from React Native
EnvironmentManager.get('SOME_VARIABLE')
  .then(val => {
    console.log('value of SOME_VARIABLE is: ', val);

  })
  .catch(err => {
    console.error('womp womp: ', err.message);
  });

The only problem I see with this, that it's async code. There is a pull request to support getSync. Check it out too.

https://github.com/joeferraro/react-native-env/pull/9

like image 3
leonfs Avatar answered Oct 03 '22 18:10

leonfs


Step 1: Create separate component like this Component name : pagebase.js
Step 2: Inside this use code this

    export const BASE_URL = "http://192.168.10.10:4848/";
    export const API_KEY = 'key_token';

Step 3: Use it in any component, for using it first import this component then use it. Import it and use it:

        import * as base from "./pagebase";

        base.BASE_URL
        base.API_KEY
like image 4
Jitendra Suthar Avatar answered Oct 03 '22 19:10

Jitendra Suthar