React Native Expo环境变量

14

所以我很满意这篇文章和其他文章中解释的环境变量的概念 https://www.freecodecamp.org/news/how-to-gracefully-use-environment-variables-in-a-react-native-app/

太好了,我已经将SOMETHING="something"存储了下来,所以我可以使用env.SOMETHING或其他方式

我有点困惑的部分是你在哪里保存实时变量

我不想采用像这样的解决方案,因为它似乎仍然会使您的密钥非常公开,并且您只是基于if语句选择环境

使用expo react native管理环境

例如,在我们部署Express应用程序时,我们指定

let endPointURL = env.endPointURL

然后我们在本地保留该变量的一个版本,当它到了AWS时,它会被AWS服务器覆盖,如此处所述。

我只是想知道Android和iOS版本是否也存在类似的情况(在各自的商店中)或通过Expo?

谢谢大家

5个回答

16

老实说,我认为他们处理这件事的方式有点傻。可能有比这更好的方法,但我觉得我按照他们的文档建议进行了操作。

https://docs.expo.io/versions/latest/distribution/release-channels/#using-release-channels-for-environment-variable-configuration

他们有一个代码片段,建议您创建一个函数来查看发布配置本身。
我理解为您可能会做类似下面的代码,并将环境变量存储在variables.js文件中,并按如下方式提取您的环境变量。
import Constants from 'expo-constants';

export const prodUrl = "https://someapp.herokuapp.com";

const ENV = {
  dev: {
    apiUrl: "http://localhost:3000"
  },
  staging: {
    apiUrl: prodUrl
  },
  prod: {
    apiUrl: prodUrl
  }
};

function getEnvVars(env = "") {
  if (env === null || env === undefined || env === "") return ENV.dev;
  if (env.indexOf("dev") !== -1) return ENV.dev;
  if (env.indexOf("staging") !== -1) return ENV.staging;
  if (env.indexOf("prod") !== -1) return ENV.prod;
}

export default getEnvVars(Constants.manifest.releaseChannel);

编辑:

现在Expo支持将配置文件命名为app.config.jsapp.config.ts,我们可以使用dotenv。请参考:https://docs.expo.io/guides/environment-variables/#using-a-dotenv-file


2
在深入研究了这个问题之后,我会选择你的答案@Caleb。真遗憾没有更简单的机制来解决这个问题!最终我保留了两个文件夹 - 一个用于生产环境,另一个用于开发环境,并使用不同的文件夹来存储环境变量,我只需使用git push和pull来保持源代码的更新。虽然很傻但它确实有效!:'D - Ash Hogarth
我本来很希望自己是错的。哎呀,大多数答案都是“离开 Expo”。 - Caleb Davenport
1
@AshHogarth的另一种解决方案可能是将两个配置文件夹放在一个仓库中,并有一个文件在需要时切换它们。将此文件添加到.gitignore中,并在每次构建时生成它。例如,config.now.js只包含module.exports = require('./config.staging/index.js') - joeytwiddle
1
我正在尝试这个,但我可以说它并不好用。Expo Web 可以获取新的环境变量,但 Android 和 iOS 应用程序却被困在一个我甚至无法更改的环境中。 - Dimitri Kopriwa

6
更简单的方法是导出env对象而不是函数:

import Constants from 'expo-constants';
import { Platform } from "react-native";

const localhost =
 Platform.OS === "ios" ? "localhost:8080" : "10.0.2.2:8080";


const ENV = {
    dev: {
      apiUrl: localhost,
      amplitudeApiKey: null,
    },
    staging: {
      apiUrl: "[your.staging.api.here]",
      amplitudeApiKey: "[Enter your key here]",
      // Add other keys you want here
    },
    prod: {
      apiUrl: "[your.production.api.here]",
      amplitudeApiKey: "[Enter your key here]",
      // Add other keys you want here
    }
};

const getEnvVars = (env = Constants.manifest.releaseChannel) => {
  if (env === null || env === undefined || env === "" || env.indexOf("dev") !== -1) return ENV.dev;
  if (env.indexOf("staging") !== -1) return ENV.staging;
  if (env.indexOf("prod") !== -1) return ENV.prod;
}

const selectedENV = getEnvVars();

export default selectedENV;

// Import
import env from '..xxx/utility/env';


你的解决方案与被接受的答案相同,只是你将方法调用分开了。被接受的答案并没有返回一个函数,它返回的是函数的结果,就像你的答案一样。 - VtoCorleone

3

很惊讶没有任何答案涉及在Expo中将环境变量存储在.env文件中。

我更喜欢将我的环境变量存储在.env文件中,因为我不想将某些变量提交到版本控制并将它们硬编码到我的应用程序代码中。

  1. 创建您的.env文件并添加您的环境变量

  2. 安装dotenv

npm install dotenv
  • 在你的app.config.js文件中,通过dotenv.env文件加载环境变量:
  • require("dotenv").config();
    
    export default {
        // config...
    }
    
    1. app.config.js 配置中,将环境变量暴露给 Expo 运行时:
    require("dotenv").config();
    
    export default {
        // rest of config...
        extra: {
            ENV_VAR: process.env.ENV_VAR
        }
    }
    

    现在你可以通过以下方式访问你的环境变量:

    import Constants from "expo-constants";
    const ENV_VAR = Constants.expoConfig.extra.ENV_VAR
    

    可选项: TypeScript

    为了让我们在代码中更方便地使用环境变量,让我们创建一个类型化的辅助工具来访问环境变量:

    import Constants from "expo-constants";
    
    export interface Env {
      ENV_VAR: string;
    }
    
    /**
     * Environment variables exposed through `app.config.js`
     * An environment variable not there? Make sure it is explicitly defined in `app.config.js`
     */
    export const env = Constants.expoConfig?.extra as Env;
    

    然后,您可以直接从env对象访问您的环境变量:
    const ENV_VAR = env.ENV_VAR
    

    可选:如果环境变量未设置,则抛出错误

    这可以很方便地防止您的应用程序在所需的环境变量未设置时运行,从而使其无法正常运行。

    在您的app.config.js中:

    // Validate all necessary environment variables are set
    const checkForEnvVariable = (envVar) => {
      if (!process.env[envVar]) {
        throw Error(`${envVar} not set! Check env.md for more information`);
      }
    };
    [
      "ENV_VAR",
      // ...
    ].forEach((envVar) => checkForEnvVariable(envVar));
    

    1

    在你的ios生成文件中,基于.env文件获取它:

    1. .env中,写下GOOGLE_MAPS_API=abcde...
    2. yarn add react-native-config
    3. cd ios
    4. pod install
    5. 在你的Objective-C编译代码中,例如AppDelegate.m
    #import "ReactNativeConfig.h"
    NSString *mapsApiKey = [ReactNativeConfig envFor:@"GOOGLE_MAPS_API"];
    [GMSServices provideAPIKey:mapsApiKey];
    

    感谢 ReactNative:将JS变量传递给AppDelegate,基于 https://github.com/luggit/react-native-config

    Android 也应该可以工作,但尚未测试/遵循 https://github.com/luggit/react-native-config。 编辑: Android 所需步骤:

    1. <meta-data android:name="com.google.android.geo.API_KEY" android:value="@string/GOOGLE_MAPS_API"/>AndroidManifest.xml 中。
    2. settings.gradle 中:
    include ':react-native-config'
    project(':react-native-config').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-config/android')
    

    rootProject.name = 'XYZ'之后:

    1. build.gradle中: apply from: project(':react-native-config').projectDir.getPath() + "/dotenv.gradle"放在import com.android.build.OutputFile下面,implementation project(':react-native-config')放在implementation "com.facebook.react:react-native:+" // From node_modules下面。

    关于在.ts.tsx.js文件中的“正常”用法,我根据https://github.com/goatandsheep/react-native-dotenv中的方法,在babel.config.jsplugins中声明"module:react-native-dotenv",并在.env中声明变量,效果非常好:

    import { ACCESS_TOKEN } from "@env";
    ...
    headers: {
      Authorization: `Bearer ${ACCESS_TOKEN}`,
      Accept: "application/json",
    },
    
    

    编辑:重要提示 eas 构建会忽略在 .gitignore 中声明的变量,因此如果你的 .env.gitignore 中,生产包将不会包含它。


    1
    我一直在为这个最后一部分苦苦思索,“eas build忽略了.gitignore声明的变量”。 - Gijsriet
    @Gijsriet,我也是 :) - Daniel Danielecki
    现在,如果您的 eas 构建失败,会出现警告:* Android 构建失败:"google-services.json" 丢失,请确保该文件存在。请记住,EAS Build 仅上传由 git 跟踪的文件。使用 EAS secrets 提供文件给 EAS Build。了解更多信息* 它会重定向到 https://docs.expo.dev/build-reference/variables/#how-to-upload-a-secret-file-and - Daniel Danielecki

    0

    要在不使用.env文件的情况下从您的shell环境传递环境变量,您可以利用expoConfig.extra功能

    步骤1:暴露变量

    更新您的app.config.jsapp.config.ts,将环境变量暴露在extra命名空间下

    例如,要暴露一个名为STAGE的环境变量:

    // app.config.ts
    
    import { ExpoConfig, ConfigContext } from 'expo/config';
    
    export default (context: ConfigContext): ExpoConfig => ({
      // ... the rest of your config
    
      // https://docs.expo.dev/versions/latest/sdk/constants/#constantsmanifest;
      extra: {
        STAGE: process.env.STAGE, // expose a stage env variable to the app
      },
    });
    

    第二步:访问变量
    通过expo-constants模块访问暴露的变量。
    例如,要访问上面示例中暴露的STAGE变量。
    import Constants from 'expo-constants';
    
    const stage = Constants.expoConfig?.extra?.STAGE;
    

    第三步:清除缓存
    很遗憾,在撰写本文时,Expo的缓存似乎也会缓存“extra”值。
    因此,如果这些值发生了变化,您必须使用“--clear”设置启动Expo以清除缓存。
    expo start --clear
    

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接