在react-native中设置环境variables?
我正在使用react-native构build一个跨平台的应用程序,但我不知道如何设置环境variables,以便我可以为不同的环境使用不同的常量。
例:
development: BASE_URL: '', API_KEY: '', staging: BASE_URL: '', API_KEY: '', production: BASE_URL: '', API_KEY: '',
而不是硬编码你的应用程序常量和切换环境(我会解释如何做到这一点),我build议使用十二个因素的build议让你的构build过程定义你的BASE_URL
和你的API_KEY
。
为了回答如何将您的环境暴露给react-native
,我build议使用Babel的babel-plugin-transform-inline-environment-variables 。
为了得到这个工作,你需要下载插件,然后你需要设置一个.babelrc
,它应该看起来像这样:
{ "presets": ["react-native"], "plugins": [ "transform-inline-environment-variables" ] }
所以如果你通过运行API_KEY=my-app-id react-native bundle
(或者start,run-ios,或者run-android)来传输你的react-native代码,那么你所要做的就是让你的代码如下所示:
const apiKey = process.env['API_KEY'];
然后巴别将用下面的代替:
const apiKey = 'my-app-id';
希望这可以帮助!
React native没有全局variables的概念。 它严格执行模块化范围 ,以提高组件的模块化和可重用性。
但有时候,您需要组件来了解其环境。 在这种情况下,定义一个Environment
组件可以调用以获取环境variables非常简单,例如:
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 (eg 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
这创build了一个单一的环境,可以从你的应用程序范围内的任何地方访问。 你必须从使用环境variables的任何组件明确地require(...)
模块,但这是一件好事。
我发现最简单的(不是最好的或理想的 )解决scheme是使用react-native-dotenv 。 您只需将“react-native-dotenv”预设添加到项目根目录下的.babelrc
文件中,如下所示:
{ "presets": ["react-native", "react-native-dotenv"] }
创build一个.env
文件并添加属性:
echo "SOMETHING=anything" > .env
然后在你的项目(JS)中:
import { SOMETHING } from 'react-native-dotenv' console.log(SOMETHING) // "anything"
在我看来,最好的select是使用react-native-config 。 它支持12个因素 。
我发现这个软件包非常有用。 您可以设置多个环境,例如开发,分期,生产。
在Android的情况下,也可以在Java类,gradle,AndroidManifest.xml等中使用variables。对于iOS,variables也可以在Obj-C类Info.plist中使用。
你只是像创build文件
-
.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'
如果你想使用不同的环境,你基本上这样设置ENVFILEvariables:
ENVFILE=.env.staging react-native run-android
或组装应用程序的生产(Android在我的情况):
cd android && ENVFILE=.env.production ./gradlew assembleRelease
用于设置环境variables的具体方法会因您使用的CI服务,构build方法,平台和工具而异。
如果您使用Buddybuild for CI构build应用程序并pipe理环境variables ,并且需要从JS访问configuration, env.js.example
使用键(具有空string值)创buildenv.js.example
,以便签入到源代码pipe理,以及使用Buddybuild在生成时生成一个env.js
文件,在post-clone
步骤中隐藏构build日志中的文件内容,如下所示:
#!/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
以免在开发过程中意外地将configuration和机密检入源代码pipe理。
然后,您可以使用Buddybuildvariables(如BUDDYBUILD_VARIANTS
)来pipe理文件的写入方式,以便更好地控制在BUDDYBUILD_VARIANTS
如何生成configuration文件。
为了解决这个问题,我使用了__DEV__
-in-native的__DEV__
。 只要你没有build立自己的生产反应,它就会自动设置为true
。
例如:
//vars.js let url, publicKey; if (__DEV__) { url = ... publicKey = ... } else { url = ... publicKey = ... } export {url, publicKey}
然后,只需import {url} from '../vars'
,您将始终得到正确的一个。 不幸的是,如果你想要两个以上的环境,这将无法正常工作,但它很简单,并且不涉及向项目添加更多的依赖关系。
我认为像下面的库可以帮助你解决这个难题的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); });
我看到的唯一的问题是,它是asynchronous代码。 有一个pull请求来支持getSync。 检查出来。
我使用了babel-plugin-transform-inline-environment-variables。
我所做的是在S3中将configuration文件放入我的不同环境中。
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
在你的应用程序中,你可能会有一个configuration文件:
const FIRSTENV = process.env['FIRSTENV'] const SECONDENV = process.env['SECONDENV']
这将被babel取代:
const FIRSTENV = 'FIRSTVALUE' const SECONDENV = 'SECONDVALUE'
记住你必须使用process.env ['STRING']不是process.env.STRING,否则将不能正确转换。
我已经为同样的问题创build了一个预生成脚本,因为我需要一些不同的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') })
而且我已经创build了一个自定义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)
你也可以有不同的env脚本:production.env.sh development.env.sh production.env.sh
然后在开始工作时将它们源代码(这只是绑定到一个别名),因此所有的sh文件都会为每个envvariables导出:
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;
@ chapinkapa的答案是好的。 自从Mobile Center不支持环境variables以来,我采取的一种方法是通过本机模块公开构buildconfiguration:
在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] }
您可以同步阅读构buildconfiguration,并在Javascript中决定如何行事。