Expo App environments for Dev, UAT and Production
Asked Answered
I

3

11

I have a React Native app built in Expo that connects to a Rest API. There are three environments for the rest api - dev, uat and production as below (example).

dev = https://dev.myapi.com/api
uat = https://uat.myapi.com/api
prod = https://prod.myapi.com/api

Depending on where the app is being used it needs to connect to the correct environment.

Running in the Expo Client = Dev API
Running in TestFlight or Internal Testing for the Play Store = UAT API
Running in the App Store or Play Store = Production API

What is the simplest way to achieve this?

Indistinct answered 17/3, 2021 at 2:2 Comment(0)
C
14

Follow below Steps

  1. Install expo-constants package. To install the package run the below command.

    npm i expo-constants

  2. Add environment.js file and paste below code.

import Constants from 'expo-constants';
import { Platform } from 'react-native';

const localhost = Platform.OS === 'ios' ? 'localhost:8080' : '10.0.2.2:8080';

const ENV = {
  dev: {
    apiUrl: 'https://dev.myapi.com/api',
    amplitudeApiKey: null,
  },
  staging: {
    apiUrl: 'https://uat.myapi.com/api',
    amplitudeApiKey: '[Enter your key here]',
    // Add other keys you want here
  },
  prod: {
    apiUrl: 'https://prod.myapi.com/api',
    amplitudeApiKey: '[Enter your key here]',
    // Add other keys you want here
  },
};

const getEnvVars = (env = Constants.manifest.releaseChannel) => {
  // What is __DEV__ ?
  // This variable is set to true when react-native is running in Dev mode.
  // __DEV__ is true when run locally, but false when published.
  if (__DEV__) {
    return ENV.dev;
  } else if (env === 'staging') {
    return ENV.staging;
  } else if (env === 'prod') {
    return ENV.prod;
  }
};

export default getEnvVars;
  1. Accessing Environment Variables
// Import getEnvVars() from environment.js
import getEnvVars from '../environment';
const { apiUrl } = getEnvVars();

/******* SESSIONS::LOG IN *******/
// LOG IN
// credentials should be an object containing phone number:
// {
//   "phone" : "9876342222"
// }
export const logIn = (credentials, jsonWebToken) =>
  fetch(`${apiUrl}/phone`, {
    method: 'POST',
    headers: {
      Authorization: 'Bearer ' + jsonWebToken,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify(credentials),
  });
  1. To create the builds use the below commands.

Dev - expo build:ios --release-channel dev

Staging - expo build:ios --release-channel staging

Production - expo build:ios --release-channel prod

Now that Expo supports config file as app.config.js or app.config.ts, we can use the dotenv. Check this: https://docs.expo.io/guides/environment-variables/#using-a-dotenv-file

Crook answered 17/3, 2021 at 12:54 Comment(2)
Does this method allow for dynamic update of the URL used by the app at run-time? Or is it determined at build-time? If it is at build-time, is there any way to have the app determine the server URL at runtime?Heptamerous
This is determined at build time because it's based on release channel names, to determine server at runtime maybe you can create a Backend Endpoint to check if that user or device should be running on which environment.Element
E
5

This can be done using different Release Channel names, lets say you have created 3 release channels this way:

expo publish --release-channel prod
expo publish --release-channel staging
expo publish --release-channel dev

then you can have a function to set environment vars accordingly:

import * as Updates from 'expo-updates';

function getEnvironment() {
  if (Updates.releaseChannel.startsWith('prod')) {
    // matches prod*
    return { envName: 'PRODUCTION', dbUrl: 'ccc', apiKey: 'ddd' }; // prod env settings
  } else if (Updates.releaseChannel.startsWith('staging')) {
    // matches staging*
    return { envName: 'STAGING', dbUrl: 'eee', apiKey: 'fff' }; // stage env settings
  } else {
    // assume any other release channel is development
    return { envName: 'DEVELOPMENT', dbUrl: 'aaa', apiKey: 'bbb' }; // dev env settings
  }
}

Refer to expo documentation for more info!

Element answered 22/9, 2021 at 13:47 Comment(0)
N
5

For those who are using Expo sdk 46(or any newer version), you can do the following way

  1. Rename the app.json to app.config.js
  2. Add API URL under extra property
export default () => ({
  expo: {
    name: '',
    slug: ''
    extra: {
      API_URL: process.env.API_URL || null,
    },
    // ...
  },
});

We can access this API using expo constants like this(wherever we want). Don't forget to import constants from Expo.

const myApi = Constants.expoConfig.extra.API_URL 
axios.get(myApi).... // using API END POINT

For Local development to access API you can do it in two ways

  1. API_URL="http:// localhost:3000" expo start
  2. Just comment the Contants.expoConfig..... and directly paste local URL like const myApi = "http:// localhost:3000"

And in eas.json

{
  "production": {
    "env": {
      "API_URL": "https://prod.example.com"
    }
  },
  "staging": {
    "env": {
      "API_URL": "https://staging.example.com"
    }
  }
}

Once we run eas build the appropriate API endpoint will be set. Refer to the same in Expo documentation https://docs.expo.dev/eas-update/environment-variables/

Nadda answered 27/8, 2022 at 11:54 Comment(1)
For now, there is no option for creating an EAS config file in javascript using "eas build:configure" command. It will create "app.json" file by default. To quickly change it to "app.config.js", change the name and add "export default" at the beginning of the file.Irade

© 2022 - 2024 — McMap. All rights reserved.