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

例子:

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

当前回答

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

其他回答

经过长时间的努力,我意识到react-native并没有正式提供这个功能。这是在babel生态系统中,所以我应该学习如何写一个babel插件…

/**
 * A simple replace text plugin in babel, such as `webpack.DefinePlugin`
 * 
 * Docs: https://github.com/jamiebuilds/babel-handbook
 */
function definePlugin({ types: t }) {
    const regExclude = /node_modules/;
    return {
        visitor: {
            Identifier(path, state) {
                const { node, parent, scope } = path;
                const { filename, opts } = state;
                const key = node.name;
                const value = opts[key];

                if (key === 'constructor' || value === undefined) { // don't replace
                    return;
                }
                if (t.isMemberExpression(parent)) { // not {"__DEV__":name}
                    return;
                }
                if (t.isObjectProperty(parent) && parent.value !== node) { // error
                    return;
                }
                if (scope.getBinding(key)) { // should in global
                    return;
                }
                if (regExclude.test(filename)) { // exclude node_modules
                    return;
                }
                switch (typeof value) {
                    case 'boolean':
                        path.replaceWith(t.booleanLiteral(value));
                        break;
                    case 'string':
                        path.replaceWith(t.stringLiteral(value));
                        break;
                    default:
                        console.warn('definePlugin only support string/boolean, so `%s` will not be replaced', key);
                        break;
                }
            },
        },
    };
}

module.exports = definePlugin;

就这样,然后你可以这样用:

module.exports = {
    presets: [],
    plugins: [
        [require('./definePlugin.js'), {
            // your environments...
            __DEV__: true,
            __URL__: 'https://example.org',
        }],
    ],
};

回答者提到的包也很棒,我也参考了metro-transform-plugins/src/inline-plugin.js。

可以使用process.env.blabla而不是process.env['blabla']访问变量。我最近让它工作,并评论了我是如何在GitHub上的一个问题上做到这一点的,因为我有一些基于公认答案的缓存问题。问题是这样的。

我发现最简单(不是最好或最理想)的解决方案是使用react-native-dotenv。你只需在你的.babelrc文件的根目录下添加"react-native-dotenv"预设,如下所示:

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

创建一个.env文件并添加属性:

echo "SOMETHING=anything" > .env

然后在你的项目(JS):

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

我使用react-native-config为我的项目设置了多个环境。README文件非常清楚地解释了如何在项目中配置库。只要确保实现Android部分的额外步骤即可。

另外,在设置多个环境时,请确保在包中指定正确的启动命令。Json,基于您的系统终端。我在windows笔记本电脑中开发了Android代码,在Macbook中开发了iOS代码,所以我各自的启动命令都在包中。Json是-

"scripts": {
        "android:dev": "SET ENVFILE=.env.dev && react-native run-android",
        "android:prod": "SET ENVFILE=.env.prod && react-native run-android",
        "ios:dev": "ENVFILE=.env.dev react-native run-ios",
        "ios:prod": "ENVFILE=.env.prod react-native run-ios",
},

如果您只需要维护一个.env文件,请考虑使用 react-native-dotenv是一个较轻的选择,尽管我在为这个库设置多个.env文件时遇到了一些问题。

如果你使用的是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"
    }
  }
}

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

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