在react-native中设置环境变量?

时间:2015-10-14 05:26:39

标签: react-native

我使用react-native来构建一个跨平台的应用程序,但我不知道如何设置环境变量,以便我可以为不同的环境设置不同的常量。

示例:

float: left

16 个答案:

答案 0 :(得分:105)

我建议您使用twelve factor建议让您的构建过程定义,而不是硬编码您的应用常量并切换环境(我将在稍后解释如何执行此操作)您的BASE_URLAPI_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或运行android)来转换您的react-native代码,那么您所要做的就是让代码看起来像这样:

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

然后巴贝尔将用以下内容取而代之:

const apiKey = 'my-app-id';

希望这有帮助!

答案 1 :(得分:36)

我找到的最简单(不是最佳理想)解决方案是使用react-native-dotenv。你只需添加" 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"

答案 2 :(得分:26)

在我看来,最好的选择是使用react-native-config。 它支持12 factor

我发现这个包非常有用。您可以设置多个环境,例如发展,分期,生产。

对于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

或用于组装生产的应用程序(在我的情况下为android):

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

答案 3 :(得分:22)

React native没有全局变量的概念。 它严格执行modular scope,以促进组件模块化和可重用性。

但有时,您需要组件了解其环境。在这种情况下,定义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(...)模块,但这是一件好事。

答案 4 :(得分:12)

我使用了内置于react-native的__DEV__ polyfill来解决这个问题。只要您没有为生产构建反应本机,它就会自动设置为true

例如:

//vars.js

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

export {url, publicKey}

然后只需import {url} from '../vars',您就会得到正确的答案。不幸的是,如果您需要两个以上的环境,这不会起作用,但它很容易,并且不会涉及为您的项目添加更多依赖项。

答案 5 :(得分:5)

用于设置环境变量的具体方法因您使用的CI服务,构建方法,平台和工具而异。

如果您正在使用Buddybuild for CI来构建应用程序和manage environment variables,并且您需要从JS访问配置,请创建一个带有键(带有空字符串值)的env.js.example以进行签入来源控制,并使用Buddybuild在env.js步骤中的构建时生成post-clone文件,从构建日志中隐藏文件内容,如下所示:

#!/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

提示:不要忘记将env.js添加到.gitignore,这样配置和秘密在开发过程中不会被意外检入源控件。

然后,您可以使用BUDDYBUILD_VARIANTSrow = [{'next': 'https://data.ratings.com/v1.0/org/576/portfolios/36/companies/?page=2', 'results': [{'earningsPerformance':'Average','liquidity': 'Strong'}, {'earningsPerformance':'Average','liquidity': 'Strong'}]}] result_count = len(row[0]["results"]) 来管理文件的编写方式,以便更好地控制构建时如何生成配置。

答案 6 :(得分:3)

我认为类似下面的库可以帮助你解决难题的缺失,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

答案 7 :(得分:3)

我为同一个问题创建了一个预构建脚本,因为我需要为不同的环境设置一些不同的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来执行 react-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)

答案 8 :(得分:1)

我使用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

每个环境文件:

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'] NOT process.env.STRING,否则它无法正常转换。

答案 9 :(得分:1)

可以使用process.env.blabla代替process.env['blabla']来访问变量。我最近做了它的工作并评论我是如何在GitHub上的一个问题上做的,因为我根据接受的答案有一些缓存问题。问题是Here

答案 10 :(得分:1)

对于最新的RN版本,您可以使用以下本机模块:https://github.com/luggit/react-native-config

答案 11 :(得分:0)

您还可以使用不同的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-variables将允许在代码中访问它们:

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

答案 12 :(得分:0)

@ chapinkapa的答案很好。我从Mobile Center不支持环境变量以来采取的一种方法是通过本机模块公开构建配置:

在android:

   @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 :(得分:0)

步骤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

答案 14 :(得分:0)

[Source]根据我的发现,默认情况下看起来像是只能进行生产和开发配置(没有暂存或其他环境)–是吗?

现在,我一直在使用一个environment.js文件,该文件可用于检测博览会发布渠道并更改以此为基础的返回变量,但是要进行构建,我需要更新非 DEV < / strong>变量返回为暂存或生产:

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;

替代品

有人在使用e​​xpo构建的项目中使用react-native-dotenv有经验吗?我很想听听你的想法

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

答案 15 :(得分:0)

如果您使用的是Expo,根据文档https://docs.expo.io/guides/environment-variables/

,有两种方法可以执行此操作

方法1 -在应用清单(app.json)中使用.extra道具:

在您的app.json文件中

{
  expo: {
    "slug": "my-app",
    "name": "My App",
    "version": "0.10.0",
    "extra": {
      "myVariable": "foo"
    }
  }
}

然后只需导入expo-constants,即可访问代码(即App.js)中的数据:

import Constants from 'expo-constants';

export const Sample = (props) => (
  <View>
    <Text>{Constants.manifest.extra.myVariable}</Text>
  </View>
);

此选项是一个很好的内置选项,不需要安装任何其他软件包。

方法2 -使用Babel来“替换”变量。这是您可能需要的方法,尤其是在使用裸露的工作流程时。其他答案已经提到了如何使用babel-plugin-transform-inline-environment-variables来实现这一点,但是我将在此处留下有关如何实现它的官方文档的链接:https://docs.expo.io/guides/environment-variables/#using-babel-to-replace-variables