在 react-native 中设置环境变量?
Setting environment variable in react-native?
我正在使用 react-native 构建跨平台应用程序,但我不知道如何设置环境变量,以便我可以为不同的环境设置不同的常量。
示例:
development:
BASE_URL: '',
API_KEY: '',
staging:
BASE_URL: '',
API_KEY: '',
production:
BASE_URL: '',
API_KEY: '',
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(...)
模块,但这是一件好事。
我建议使用 twelve factor 的建议,让您的构建过程定义你的 BASE_URL
和你的 API_KEY
.
为了回答如何将您的环境暴露给 react-native
,我建议使用 Babel 的 babel-plugin-transform-inline-environment-variables。
要实现此功能,您需要下载插件,然后需要设置 .babelrc
,它应该如下所示:
{
"presets": ["react-native"],
"plugins": [
"transform-inline-environment-variables"
]
}
因此,如果您通过 运行ning API_KEY=my-app-id react-native bundle
(或开始,运行-ios 或 运行- android) 然后你所要做的就是让你的代码看起来像这样:
const apiKey = process.env['API_KEY'];
然后 Babel 会将其替换为:
const apiKey = 'my-app-id';
我认为像以下库这样的东西可以帮助您解决难题中缺少的部分,即 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 的拉取请求。也检查一下。
用于设置环境变量的具体方法会因 CI 服务、构建方法、平台和您使用的工具而异。
如果您使用 Buddybuild 为 CI 构建应用程序和 manage environment variables,并且您需要从 JS 访问配置,请创建一个带有键的 env.js.example
(带有空字符串values) 用于签入源代码控制,并在 post-clone
步骤的构建时使用 Buddybuild 生成一个 env.js
文件,从构建日志中隐藏文件内容,如下所示:
#!/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 variables 来管理文件的写入方式,例如 BUDDYBUILD_VARIANTS
,以便更好地控制在构建时生成配置的方式。
你也可以有不同的环境脚本:production.env.sh development.env.sh production.env.sh
然后在开始工作时获取它们[这只是绑定到一个别名]
所以所有的 sh 文件都是为每个环境变量导出的:
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;
我认为最好的选择是使用 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
@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 中决定您的行为方式。
为了解决这个问题,我使用了react-native内置的__DEV__
polyfill。只要您不为生产构建 React Native,它就会自动设置为 true
。
例如:
//vars.js
let url, publicKey;
if (__DEV__) {
url = ...
publicKey = ...
} else {
url = ...
publicKey = ...
}
export {url, publicKey}
然后import {url} from '../vars'
你总能找到正确的。不幸的是,如果您需要两个以上的环境,这将不起作用,但它很简单,并且不涉及向您的项目添加更多依赖项。
我用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']
而不是 process.env.STRING
,否则将无法正确转换。
我已经为同样的问题创建了一个预构建脚本,因为我需要一些不同的 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 运行..
我的包裹-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)
我找到的最简单(不是最佳或理想)解决方案是使用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"
可以使用 process.env.blabla
而不是 process.env['blabla']
访问变量。我最近让它工作并评论了我是如何在 GitHub 上的一个问题上做的,因为根据接受的答案,我在缓存方面遇到了一些问题。 Here 是问题。
第 1 步:像这样创建单独的组件
组件名称:pagebase.js
第 2 步:在此使用代码
export const BASE_URL = "http://192.168.10.10:4848/";
export const API_KEY = 'key_token';
第三步:在任何组件中使用它,要使用它首先导入这个组件然后使用它。
导入并使用它:
import * as base from "./pagebase";
base.BASE_URL
base.API_KEY
对于最新的 RN 版本,您可以使用这个原生模块:https://github.com/luggit/react-native-config
[Source] 根据我的发现,默认情况下,它似乎只能进行生产和开发配置(没有暂存或其他环境)——对吗?
现在,我一直在使用 environment.js 文件,该文件可用于检测 expo 发布渠道并根据该渠道更改返回的变量,但为了构建,我需要更新非 DEV 变量返回为暂存或生产:
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;
备选方案
有没有人有使用 react-native-dotenv 构建 expo 项目的经验?我很想听听你的想法
如果您使用的是 Expo,根据文档有 2 种方法可以做到这一点 https://docs.expo.io/guides/environment-variables/
方法 #1 - 在应用程序清单中使用 .extra
道具 (app.json):
在您的 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>
);
这个选项是一个很好的built-in选项,它不需要安装任何其他包。
方法#2 - 使用 Babel 来“替换”变量。这是您可能需要的方法,尤其是在您使用裸工作流程时。其他答案已经提到如何使用 babel-plugin-transform-inline-environment-variables
来实现它,但我将在此处将 link 留给官方文档以了解如何实现它:https://docs.expo.io/guides/environment-variables/#using-babel-to-replace-variables
我使用 react-native-config 为我的项目设置多个环境。 README 文件非常清楚地解释了如何在项目中配置库。只需确保为 Android 部分实施 额外步骤。
此外,在设置多个环境时,请确保根据您的系统终端在 package.json 中指定正确的启动命令。我在 windows 笔记本电脑上开发了 Android 代码,在 Macbook 上开发了 iOS 代码,所以我在 package.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 文件时确实遇到了一些问题。
你好,如果你遇到这个问题试试这个,这对我有用,稍后谢谢我
在bable.js
plugins: [
[
"module:react-native-dotenv",
{
moduleName: "react-native-dotenv",
},
],
],
使用
import { YOURAPIKEY } from "react-native-dotenv";
inseted of
import { YOURAPIKEY } from "@env";
不要传递这些变量,如 VAR=value react-native run-android
或 VAR=value react-native run-ios
. 这些变量只有在我们在 start
命令中传递它们时才能访问,即 VAR=value react-native start --reset-cache
.
您可以通过 3 个简单的步骤实现:-
通过 运行 npm i babel-plugin-transform-inline-environment-variables --save-dev
安装 babel-plugin-transform-inline-environment-variables
。
将 "plugins": [ "transform-inline-environment-variables" ]
添加到您的 .bablerc
或 babel.config.js
.
在启动 metro bundler 时传递变量,即 VAR=value reacti-native start --reset-cache
,不要在 react-native run-android
或 [=21= 中传递这些变量] 命令。
请记住需要使用 --reset-cache
标志,否则将不会应用变量的更改。
经过一番折腾,发现react-native官方并没有提供这个功能。这是在 babel-ecosystem 中,所以我应该学习如何编写 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
。
我正在使用 react-native 构建跨平台应用程序,但我不知道如何设置环境变量,以便我可以为不同的环境设置不同的常量。
示例:
development:
BASE_URL: '',
API_KEY: '',
staging:
BASE_URL: '',
API_KEY: '',
production:
BASE_URL: '',
API_KEY: '',
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(...)
模块,但这是一件好事。
我建议使用 twelve factor 的建议,让您的构建过程定义你的 BASE_URL
和你的 API_KEY
.
为了回答如何将您的环境暴露给 react-native
,我建议使用 Babel 的 babel-plugin-transform-inline-environment-variables。
要实现此功能,您需要下载插件,然后需要设置 .babelrc
,它应该如下所示:
{
"presets": ["react-native"],
"plugins": [
"transform-inline-environment-variables"
]
}
因此,如果您通过 运行ning API_KEY=my-app-id react-native bundle
(或开始,运行-ios 或 运行- android) 然后你所要做的就是让你的代码看起来像这样:
const apiKey = process.env['API_KEY'];
然后 Babel 会将其替换为:
const apiKey = 'my-app-id';
我认为像以下库这样的东西可以帮助您解决难题中缺少的部分,即 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 的拉取请求。也检查一下。
用于设置环境变量的具体方法会因 CI 服务、构建方法、平台和您使用的工具而异。
如果您使用 Buddybuild 为 CI 构建应用程序和 manage environment variables,并且您需要从 JS 访问配置,请创建一个带有键的 env.js.example
(带有空字符串values) 用于签入源代码控制,并在 post-clone
步骤的构建时使用 Buddybuild 生成一个 env.js
文件,从构建日志中隐藏文件内容,如下所示:
#!/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 variables 来管理文件的写入方式,例如 BUDDYBUILD_VARIANTS
,以便更好地控制在构建时生成配置的方式。
你也可以有不同的环境脚本:production.env.sh development.env.sh production.env.sh
然后在开始工作时获取它们[这只是绑定到一个别名] 所以所有的 sh 文件都是为每个环境变量导出的:
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;
我认为最好的选择是使用 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
@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 中决定您的行为方式。
为了解决这个问题,我使用了react-native内置的__DEV__
polyfill。只要您不为生产构建 React Native,它就会自动设置为 true
。
例如:
//vars.js
let url, publicKey;
if (__DEV__) {
url = ...
publicKey = ...
} else {
url = ...
publicKey = ...
}
export {url, publicKey}
然后import {url} from '../vars'
你总能找到正确的。不幸的是,如果您需要两个以上的环境,这将不起作用,但它很简单,并且不涉及向您的项目添加更多依赖项。
我用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']
而不是 process.env.STRING
,否则将无法正确转换。
我已经为同样的问题创建了一个预构建脚本,因为我需要一些不同的 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 运行..
我的包裹-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)
我找到的最简单(不是最佳或理想)解决方案是使用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"
可以使用 process.env.blabla
而不是 process.env['blabla']
访问变量。我最近让它工作并评论了我是如何在 GitHub 上的一个问题上做的,因为根据接受的答案,我在缓存方面遇到了一些问题。 Here 是问题。
第 1 步:像这样创建单独的组件
组件名称:pagebase.js
第 2 步:在此使用代码
export const BASE_URL = "http://192.168.10.10:4848/";
export const API_KEY = 'key_token';
第三步:在任何组件中使用它,要使用它首先导入这个组件然后使用它。 导入并使用它:
import * as base from "./pagebase";
base.BASE_URL
base.API_KEY
对于最新的 RN 版本,您可以使用这个原生模块:https://github.com/luggit/react-native-config
[Source] 根据我的发现,默认情况下,它似乎只能进行生产和开发配置(没有暂存或其他环境)——对吗?
现在,我一直在使用 environment.js 文件,该文件可用于检测 expo 发布渠道并根据该渠道更改返回的变量,但为了构建,我需要更新非 DEV 变量返回为暂存或生产:
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;
备选方案
有没有人有使用 react-native-dotenv 构建 expo 项目的经验?我很想听听你的想法
如果您使用的是 Expo,根据文档有 2 种方法可以做到这一点 https://docs.expo.io/guides/environment-variables/
方法 #1 - 在应用程序清单中使用 .extra
道具 (app.json):
在您的 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>
);
这个选项是一个很好的built-in选项,它不需要安装任何其他包。
方法#2 - 使用 Babel 来“替换”变量。这是您可能需要的方法,尤其是在您使用裸工作流程时。其他答案已经提到如何使用 babel-plugin-transform-inline-environment-variables
来实现它,但我将在此处将 link 留给官方文档以了解如何实现它:https://docs.expo.io/guides/environment-variables/#using-babel-to-replace-variables
我使用 react-native-config 为我的项目设置多个环境。 README 文件非常清楚地解释了如何在项目中配置库。只需确保为 Android 部分实施 额外步骤。
此外,在设置多个环境时,请确保根据您的系统终端在 package.json 中指定正确的启动命令。我在 windows 笔记本电脑上开发了 Android 代码,在 Macbook 上开发了 iOS 代码,所以我在 package.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 文件时确实遇到了一些问题。
你好,如果你遇到这个问题试试这个,这对我有用,稍后谢谢我
在bable.js
plugins: [
[
"module:react-native-dotenv",
{
moduleName: "react-native-dotenv",
},
],
],
使用
import { YOURAPIKEY } from "react-native-dotenv";
inseted of
import { YOURAPIKEY } from "@env";
不要传递这些变量,如 VAR=value react-native run-android
或 VAR=value react-native run-ios
. 这些变量只有在我们在 start
命令中传递它们时才能访问,即 VAR=value react-native start --reset-cache
.
您可以通过 3 个简单的步骤实现:-
通过 运行
npm i babel-plugin-transform-inline-environment-variables --save-dev
安装babel-plugin-transform-inline-environment-variables
。将
"plugins": [ "transform-inline-environment-variables" ]
添加到您的.bablerc
或babel.config.js
.在启动 metro bundler 时传递变量,即
VAR=value reacti-native start --reset-cache
,不要在react-native run-android
或 [=21= 中传递这些变量] 命令。
请记住需要使用 --reset-cache
标志,否则将不会应用变量的更改。
经过一番折腾,发现react-native官方并没有提供这个功能。这是在 babel-ecosystem 中,所以我应该学习如何编写 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
。