首页 文章

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

提问于
浏览
90

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

例:

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

13 回答

  • 20

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

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

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

    const apiKey = 'my-app-id';
    

    希望这可以帮助!

  • 0

    我找到的最简单(不是最好或最理想)的解决方案是使用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"
    
  • 1

    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
    

    my-component.js

    var Environment = require('./environment.js')
    
    ...somewhere in your code...
    var url = Environment.BASE_URL
    

    这将创建一个singleton环境,可以从应用范围内的任何位置访问 . 您必须从使用环境变量的任何组件中明确 require(...) 模块,但这是一件好事 .

  • 10

    在我看来,最好的选择是使用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
    
  • 89

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

    例如 . :

    //vars.js
    
    let url, publicKey;
    if (__DEV__) {
      url = ...
      publicKey = ...
    } else {
      url = ...
      publicKey = ...
    }
    
    export {url, publicKey}
    

    然后只是 import {url} from '../vars' 而你'll always get the correct one. Unfortunately, this wont work if you want more than two environments, but its easy and doesn' t涉及为你的项目添加更多的依赖项 .

  • 29

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

    如果您正在使用Buddybuild for CI来构建应用程序和manage environment variables,并且您需要从JS访问配置,请使用键(带有空字符串值)创建 env.js.example 以检入源代码控制,并使用Buddybuild生成 env.jspost-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
    

    Tip: 不要忘记将 env.js 添加到 .gitignore ,因此配置和秘密不会在开发过程中意外检查到源代码管理中 .

    然后,您可以使用Buddybuild variables来管理文件的编写方式,例如 BUDDYBUILD_VARIANTS ,以便更好地控制在构建时生成配置的方式 .

  • 1

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

  • 18

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

    这将被巴贝尔取代至:

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

    请记住,你必须使用process.env ['STRING'] NOT process.env.STRING,否则它将无法正常转换 .

  • 1

    我已经为同一个问题创建了一个预构建脚本,因为我需要为不同的环境提供一些不同的api endpoints

    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)
    
  • 4

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

  • 2

    您还可以使用不同的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;
    
  • 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中决定您将如何表现 .

  • 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
    

相关问题