Установка переменной среды в реакции-родной?

Я использую response-native для создания кросс-платформенного приложения, но я не знаю, как установить переменную среды, чтобы я мог иметь разные константы для разных сред.

Пример:

development: 
  BASE_URL: '',
  API_KEY: '',
staging: 
  BASE_URL: '',
  API_KEY: '',
production:
  BASE_URL: '',
  API_KEY: '',

Ответ 1

Вместо жесткого кодирования ваших констант приложения и включения среды (я объясню, как это сделать в данный момент), я предлагаю использовать двенадцать факторов, чтобы ваш процесс сборки определял ваш BASE_URL и ваш API_KEY.

Чтобы ответить, как выставить свою среду в react-native, я предлагаю использовать Babel babel-plugin-transform-inline-environment-variables.

Чтобы получить эту работу, вам нужно загрузить плагин, а затем вам нужно настроить .babelrc, и он должен выглядеть примерно так:

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

Итак, если вы перекроете свой реактивный код, запустив API_KEY=my-app-id react-native bundle (или запустите, запустите ios или run-android), вам нужно всего лишь сделать код:

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

И тогда Бабель заменит это:

const apiKey = 'my-app-id';

Надеюсь, это поможет!

Ответ 2

Самое простое (не лучшее или идеальное) решение, которое я нашел, это использовать react-native-dotenv. Вы просто добавляете предварительный набор "реагировать-родной-дотень" в свой .babelrc файл в корне проекта так:

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

Создайте файл .env и добавьте свойства:

echo "SOMETHING=anything" > .env

Затем в вашем проекте (JS):

import { SOMETHING } from 'react-native-dotenv'
console.log(SOMETHING) // "anything"

Ответ 3

На мой взгляд, лучшим вариантом является использование react-native-config. Он поддерживает 12 фактор.

Я нашел этот пакет чрезвычайно полезным. Вы можете установить несколько сред, например. разработка, постановка, производство.

В случае Android переменные доступны также в Java-классах, gradle, AndroidManifest.xml и т.д. В случае iOS переменные доступны также в классах Obj-C, Info.plist.

Вы просто создаете такие файлы, как

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

Вы заполняете эти файлы ключом, значения типа

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

а затем просто используйте его:

import Config from 'react-native-config'

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

Если вы хотите использовать разные среды, вы в основном устанавливаете переменную ENVFILE следующим образом:

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

или для сборки приложения для производства (андроид в моем случае):

cd android && ENVFILE=.env.production ./gradlew assembleRelease

Ответ 4

React native не имеет понятия глобальных переменных. Он строго соблюдает модульную область, чтобы повысить модульность компонентов и возможность повторного использования.

Иногда, однако, вам нужны компоненты, которые должны знать об окружающей среде. В этом случае очень просто определить модуль Environment, который компоненты могут затем вызвать для получения переменных среды, например:

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

мой-component.js

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

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

Это создает среду singleton, к которой можно получить доступ из любой точки вашего приложения. Вы должны явно указать require(...) модуль из любых компонентов, которые используют переменные среды, но это хорошо.

Ответ 5

Я использовал __DEV__ polyfill, который встроен в реакцию-native, чтобы решить эту проблему. Он автоматически устанавливается на true, пока вы не строите реакцию на родной для производства.

Например:

//vars.js

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

export {url, publicKey}

Затем просто import {url} from '../vars', и вы всегда получите правильный. К сожалению, это не будет работать, если вы хотите более двух сред, но это легко и не требует добавления дополнительных зависимостей к вашему проекту.

Ответ 6

Конкретный метод, используемый для установки переменных среды, зависит от службы CI, подхода к сборке, платформы и инструментов, которые вы используете.

Если вы используете Buddybuild for CI для создания приложения и управления переменными среды, и вам нужен доступ к конфигурации из JS, создайте env.js.example с ключами (с пустыми строковыми значениями) для регистрации в системе контроля env.js.example и Используйте Buddybuild для создания файла env.js во время сборки на этапе post-clone, скрывая содержимое файла из журналов сборки, например, так:

#!/usr/bin/env bash

ENVJS_FILE="$BUDDYBUILD_WORKSPACE/env.js"

# Echo what 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

Совет: не забудьте добавить env.js в .gitignore чтобы настройки и секреты не env.js в .gitignore env.js .gitignore случайно при разработке.

Затем вы можете управлять тем, как файл будет записан, используя переменные BUDDYBUILD_VARIANTS, например, BUDDYBUILD_VARIANTS, чтобы получить больший контроль над тем, как создается ваша конфигурация во время сборки.

Ответ 7

Я думаю, что что-то вроде следующей библиотеки может помочь вам решить недостающий бит головоломки - функцию getPlatform().

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);
  });

Единственная проблема, с которой я вижу, - это асинхронный код. Для поддержки getSync существует запрос на вытягивание. Проверьте это тоже.

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

Ответ 8

Я создал предварительную сборку script для той же самой проблемы, потому что мне нужны некоторые разные точки api для разных сред

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')
})

И я создал пользовательский npm run scripts, чтобы выполнить run-native run..

Мой пакет-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",
    ...
}

Затем в моих сервисах компоненты просто импортируют автоматически сгенерированный файл:

import config from '../constants/config'

fetch(`${config.API_URL}/login`, params)

Ответ 9

Я использую babel-plugin-transform-inline-environment-variables.

Что я сделал, так это поместил файлы конфигурации в S3 с моими различными средами.

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

КАЖДЫЙ env файл:

FIRSTENV=FIRSTVALUE
SECONDENV=SECONDVALUE

После этого я добавил новый скрипт в мой package.json который запускает скрипт для комплектации

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

В вашем приложении вы, вероятно, будете иметь файл конфигурации, который имеет:

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

который будет заменен на babel:

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

ПОМНИТЕ, что вы должны использовать process.env['STRING'] НЕ process.env.STRING иначе он не будет преобразован должным образом.

Ответ 10

[Источник] Из того, что я обнаружил, похоже, что по умолчанию можно выполнять только конфигурации для производства и разработки (без промежуточных или других сред) - это правильно?

Прямо сейчас я использую файл environment.js, который можно использовать для обнаружения каналов выпуска expo и изменения возвращаемых переменных, основываясь на этом, но для сборки мне нужно обновить переменную DEV non-, возвращаемую в качестве промежуточной или продукт:

import { Constants } from 'expo';
import { Platform } from 'react-native';
const localhost = Platform.OS === 'ios' ? 'http://localhost:4000/' : 'http://10.0.2.2:4000/';
const ENV = {
  dev: {
    apiUrl: localhost,
  },
  staging: {
    apiUrl: 'https://your-staging-api-url-here.com/'
  },
  prod: {
    apiUrl: 'https://your-prod-api-url-here.com/'
  },
}
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 {
    // When publishing to production, change this to 'ENV.prod' before running an 'expo build'
    return ENV.staging;
  }
}
export default getEnvVars;

альтернативы

у кого-нибудь есть опыт использования response-native-dotenv для проектов, построенных с помощью expo? Я хотел бы услышать ваши мысли

https://github.com/zetachang/react-native-dotenv

Ответ 11

у вас также могут быть разные сценарии env: production.env.sh development.env.sh production.env.sh

И затем отправьте их туда, когда вы начинаете работать [который просто привязан к псевдониму] поэтому для каждого файла sh есть экспорт для каждой переменной env:

export SOME_VAR=1234
export SOME_OTHER=abc

И затем добавление переменных babel-plugin-transform-inline-environment позволит получить доступ к ним в коде:

export const SOME_VAR: ?string = process.env.SOME_VAR;
export const SOME_OTHER: ?string = process.env.SOME_OTHER;

Ответ 12

@chapinkapa ответ хороший. Подход, который я предпринял после того, как Mobile Center не поддерживает переменные среды, заключается в том, чтобы разоблачить конфигурацию сборки через собственный модуль:

В андроиде:

   @Override
    public Map<String, Object> getConstants() {
        final Map<String, Object> constants = new HashMap<>();
        String buildConfig = BuildConfig.BUILD_TYPE.toLowerCase();
        constants.put("ENVIRONMENT", buildConfig);
        return constants;
    } 

или на ios:

  override func constantsToExport() -> [String: Any]! {
    // debug/ staging / release
    // on android, I can tell the build config used, but here I use bundle name
    let STAGING = "staging"
    let DEBUG = "debug"

    var environment = "release"
    if let bundleIdentifier: String = Bundle.main.bundleIdentifier {
      if (bundleIdentifier.lowercased().hasSuffix(STAGING)) {
        environment = STAGING
      } else if (bundleIdentifier.lowercased().hasSuffix(DEBUG)){
        environment = DEBUG
      }
    }

    return ["ENVIRONMENT": environment]
  }

Вы можете прочитать конфигурацию сборки синхронно и выбрать в Javascript, как вы будете себя вести.

Ответ 13

Доступ к переменным можно получить с помощью process.env.blabla вместо process.env['blabla']. Недавно я сделал это и прокомментировал, как я это сделал по проблеме GitHub, потому что у меня были проблемы с кешем на основе принятого ответа. Здесь является проблема.

Ответ 14

Шаг 1. Создайте отдельный компонент, например, это имя компонента: pagebase.js
Шаг 2: внутри этого кода использования это

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

Шаг 3: Используйте его в любом компоненте, для использования сначала импортируйте этот компонент, а затем используйте его. Импортируйте это и используйте это:

        import * as base from "./pagebase";

        base.BASE_URL
        base.API_KEY