Impostazione della variabile d'ambiente in reattivo-nativo?


152

Sto utilizzando Reattivo nativo per creare un'app multipiattaforma, ma non so come impostare la variabile di ambiente in modo da poter avere costanti diverse per ambienti diversi.

Esempio:

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

puoi provare questoimport {Platform} from 'react-native'; console.log(Platform);
Praveen Prasad,

Risposte:


138

Invece di codificare a fondo le costanti della tua app e fare un passaggio sull'ambiente (ti spiego in un momento), ti suggerisco di utilizzare il suggerimento di dodici fattori per far sì che il tuo processo di compilazione definisca tu BASE_URLe il tuo API_KEY.

Per rispondere a come esporre il tuo ambiente react-native, ti suggerisco di usare le variabili di babel-plugin-transform-inline-environment-variabili .

Per far funzionare tutto ciò è necessario scaricare il plug-in e quindi sarà necessario impostare un .babelrce dovrebbe essere simile al seguente:

{
  "presets": ["react-native"],
  "plugins": [
    "transform-inline-environment-variables"
  ]
}

E quindi se traspili il tuo codice di reazione nativo eseguendo API_KEY=my-app-id react-native bundle(o avviando , run-ios o run-android), tutto ciò che devi fare è avere il tuo codice simile al seguente:

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

E poi Babel lo sostituirà con:

const apiKey = 'my-app-id';

Spero che questo ti aiuti!


7
Sembra un'ottima soluzione, ma non funziona per me a RN@0.37.0. L'unica proprietà process.envè NODE_ENV.
Adam Faryna,

2
Vedi la risposta sotto di Jack Zheng ... non puoi accedere alla variabile tramite process.env.API_KEY... usa process.env['API_KEY']invece
Steven Yap

6
Sto ottenendo process.env ['API_KEY'] come non definito. Qualcuno può aiutarmi a impostare questo
user1106888

2
Ho avuto lo stesso problema: indefinito
Guto Marrara Marzagao,

7
Funziona per me in v0.56. Devi cancellare la cache del bundler eseguendola react-native start --reset-cacheogni volta che modifichi le variabili di ambiente.
soheilpro,

55

La soluzione più semplice (non la migliore o l' ideale ) che ho trovato è stata la reattività nativa-dotenv . È sufficiente aggiungere il preset "reazioni-nativo-dotenv" al .babelrcfile nella radice del progetto in questo modo:

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

Crea un .envfile e aggiungi proprietà:

echo "SOMETHING=anything" > .env

Quindi nel tuo progetto (JS):

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

1
Speravo in una soluzione basata su .env. Grazie!
Anshul Koka,

3
@Slavo Vojacek Come posso utilizzarlo per configurare ad esempio uno base_urlper entrambi staginge production?
Compaq LE2202x

@ CompaqLE2202x Non sono sicuro di aver capito? Stai chiedendo di utilizzare .envfile diversi (per ambiente) o di riutilizzare alcuni dei tuoi valori in .envfile diversi , in modo da non duplicarli attraverso, ad esempio, Staging e Production?
Slavo Vojacek,

5
@SlavoVojacek Sto chiedendo .envfile diversi per ambiente, diciamo staginge production.
Compaq LE2202x

@SlavoVojacek non hai potuto sovrascrivere i valori in una fase CI o durante la distribuzione?
mgamsjager il

37

A mio avviso, l'opzione migliore è utilizzare la configurazione di reattivo-nativo . Supporta 12 fattori .

Ho trovato questo pacchetto estremamente utile. È possibile impostare più ambienti, ad esempio sviluppo, stadiazione, produzione.

Nel caso di Android, le variabili sono disponibili anche nelle classi Java, Gradle, AndroidManifest.xml ecc. Nel caso di iOS, le variabili sono disponibili anche nelle classi Obj-C, Info.plist.

Devi solo creare file come

  • .env.development
  • .env.staging
  • .env.production

Riempi questi file con chiave, valori come

API_URL=https://myapi.com
GOOGLE_MAPS_API_KEY=abcdefgh

e poi basta usarlo:

import Config from 'react-native-config'

Config.API_URL  // 'https://myapi.com'
Config.GOOGLE_MAPS_API_KEY  // 'abcdefgh'

Se vuoi usare ambienti diversi, in pratica imposti la variabile ENVFILE in questo modo:

ENVFILE=.env.staging react-native run-android

o per assemblare app per la produzione (Android nel mio caso):

cd android && ENVFILE=.env.production ./gradlew assembleRelease

9
Vale la pena notare che nel README afferma che questo modulo non offusca o crittografa i segreti per il packaging, quindi non conservare le chiavi sensibili in .env. È praticamente impossibile impedire agli utenti di decodificare i segreti delle app mobili, quindi progetta la tua app (e le API) tenendo presente questo
aspetto

Il fatto è che non funzionerà con alcuni framework come Twitter che richiede che siano impostati come com.twitter.sdk.android.CONSUMER_KEY nel tuo .env
thibaut noah

Se intendi mettere la chiave all'interno del Manifest, l'estensione la supporta. Non è appena descritto in questa risposta. È possibile utilizzare le variabili nei file XML, Java e JS.
sfratini,

4
Rea-native-config non funziona con RN 0,56, presenta problemi irrisolti e non viene mantenuto per oltre 6 mesi. Il problema che la strega uccide nel suo utilizzo in RN è github.com/luggit/react-native-config/issues/267 , ecco alcuni hack per farlo funzionare github.com/luggit/react-native-config/issues/285
Marecky

24

React native non ha il concetto di variabili globali. Fa applicare rigorosamente l' ambito modulare , al fine di promuovere la modularità e la riusabilità dei componenti.

A volte, tuttavia, sono necessari componenti per essere consapevoli del loro ambiente. In questo caso è molto semplice definire un Environmentmodulo che i componenti possono quindi chiamare per ottenere variabili di ambiente, ad esempio:

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

Questo crea un ambiente singleton a cui è possibile accedere da qualsiasi parte all'interno dell'ambito della tua app. Devi esplicitamente require(...)il modulo da qualsiasi componente che utilizza le variabili di ambiente, ma questa è una buona cosa.


19
il mio problema è come getPlatform(). Ho creato un file come questo, ma non riesco a finire la logica qui in React Native
Damon Yuan,

@DamonYuan dipende interamente da come stai configurando i tuoi pacchetti. Non ho idea di cosa significhi, stagingo productionaddirittura, perché dipende dal tuo ambiente. Ad esempio, se si desidera gusti diversi per IOS vs Android, allora è possibile inizializzare Ambiente importandolo tuoi index.ios.jse index.android.jsdei file e l'impostazione della piattaforma lì, ad es Environment.initialize('android').
insieme il

@DamonYuan fa quello che metto aiuto o hai bisogno di qualche chiarimento in più?
Chapinkapa,

Questo è molto bello quando hai il controllo del codice. Sto eseguendo un modulo di terza parte che si basa su process.env, quindi ...
enapupe,

2
Se crei un env.jsfile, assicurati di ignorarlo dai check-in al repository e di copiare le chiavi utilizzate, con valori di stringa vuoti, in un altro env.js.examplefile che esegui il check-in in modo che altri possano costruire la tua app più facilmente. Se si accede accidentalmente ai segreti del progetto, prendere in considerazione la riscrittura della cronologia per rimuoverli non solo dalla fonte ma dalla cronologia della stessa.
Josh Habdas,

17

Ho usato il __DEV__polyfill incorporato in reattivo per risolvere questo problema. Viene automaticamente impostato su truefino a quando non si crea reattivo nativo per la produzione.

Per esempio:

//vars.js

let url, publicKey;
if (__DEV__) {
  url = ...
  publicKey = ...
} else {
  url = ...
  publicKey = ...
}

export {url, publicKey}

Quindi basta import {url} from '../vars'e otterrai sempre quello corretto. Sfortunatamente, questo non funzionerà se vuoi più di due ambienti, ma è facile e non comporta l'aggiunta di più dipendenze al tuo progetto.


conosci un modo per "deviare" DEV a TRUE anche quando crei una versione di build in xcode?
realtebo,

1
No. Devo solo commentare le variabili prod e quindi copiare incollare le variabili dev nella sezione prod quando voglio fare una build di rilascio con variabili dev.
Registro

1
Ho trovato questa la soluzione più elegante
Dani Sh90,

5

Il metodo specifico utilizzato per impostare le variabili di ambiente varia in base al servizio CI, all'approccio alla costruzione, alla piattaforma e agli strumenti che stai utilizzando.

Se stai usando Buddybuild per CI per creare un'app e gestire variabili di ambiente e hai bisogno di accedere alla configurazione da JS, crea un env.js.examplecon le chiavi (con valori di stringa vuoti) per il check-in al controllo del codice sorgente e usa Buddybuild per produrre un env.jsfile in fase di compilazione nel post-clonepassaggio, nascondendo il contenuto del file dai registri di compilazione, in questo modo:

#!/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

Suggerimento: non dimenticate di aggiungere env.jsal .gitignoremodo config e segreti non vengono controllati in controllo del codice sorgente per caso durante lo sviluppo.

È quindi possibile gestire il modo in cui il file viene scritto usando le variabili Buddybuild come BUDDYBUILD_VARIANTS, ad esempio, per ottenere un maggiore controllo su come viene prodotta la configurazione al momento della creazione.


nel complesso mi piace l'idea, ma come funziona la env.js.exampleparte? diciamo che voglio avviare l'app nel mio ambiente locale. se il mio env.jsfile è in gitignore e env.js.exampleviene utilizzato come contorno, env.js.examplenon è un'estensione JS legittima, quindi sono solo un po 'confuso su cosa intendevi con questa parte
volk,

@volk Il env.js.examplefile si trova nella base di codice come documento di riferimento, una fonte canonica di verità su quali chiavi di configurazione vuole usare l'app. Descrive sia le chiavi necessarie per eseguire l'app, sia il nome file previsto una volta copiato e rinominato. Lo schema è comune nelle app Ruby usando la gemma dotenv , da cui ho sollevato lo schema.
Josh Habdas,

3

Penso che qualcosa come la seguente libreria potrebbe aiutarti a risolvere il pezzo mancante del puzzle, la funzione 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);
  });

L'unico problema che vedo in questo è che si tratta di un codice asincrono. Esiste una richiesta pull per supportare getSync. Dai un'occhiata anche a questo.

https://github.com/joeferraro/react-native-env/pull/9


3
Eseguito l'upgrade per fornire un approccio alternativo non menzionato. Nessuna taglia adatta a tutti.
Josh Habdas,

L'asynch pull req è stato unito in
jcollum il

5
React-native-env non sembra supportare Android. Qual e il punto?
jcollum,

3

ho creato uno script pre-build per lo stesso problema perché ho bisogno di alcuni endpoint API diversi per gli ambienti diversi

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')
})

E ho creato un'abitudine npm run scriptsper eseguire la corsa reattiva nativa ...

Il mio pacchetto-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",
    ...
}

Quindi nei componenti dei miei servizi è sufficiente importare il file generato automaticamente:

import config from '../constants/config'

fetch(`${config.API_URL}/login`, params)

3

Passaggio 1: Creare un componente separato come questo Nome componente: pagebase.js
Passaggio 2: All'interno di questo codice utilizzare questo

    export const BASE_URL = "http://192.168.10.10:4848/";
    export const API_KEY = 'key_token';

Step 3: Usalo in qualsiasi componente, per usarlo prima importa questo componente e poi usalo. Importalo e usalo:

        import * as base from "./pagebase";

        base.BASE_URL
        base.API_KEY

2

Io uso babel-plugin-transform-inline-environment-variables.

Quello che ho fatto è stato inserire un file di configurazione all'interno di S3 con i miei diversi ambienti.

s3://example-bucket/dev-env.sh
s3://example-bucket/prod-env.sh
s3://example-bucket/stage-env.sh

OGNI file ENV:

FIRSTENV=FIRSTVALUE
SECONDENV=SECONDVALUE

Successivamente, ho aggiunto un nuovo script nel mio package.jsonche esegue uno script per il raggruppamento

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

All'interno della tua app avrai probabilmente un file di configurazione che ha:

const FIRSTENV = process.env['FIRSTENV']
const SECONDENV = process.env['SECONDENV']

che sarà sostituito da babel per:

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

RICORDA che devi usare process.env['STRING']NOT process.env.STRINGo non verrà convertito correttamente.


REMEMBER you have to use process.env['STRING'] NOT process.env.STRING or it won't convert properly.Grazie! Questo è quello che mi fa inciampare !!!
Steven Yap,

1

[Fonte] Da quello che ho trovato, sembra per impostazione predefinita, è possibile eseguire solo configurazioni di produzione e sviluppo (nessuna messa in scena o altri ambienti) - giusto?

In questo momento, sto usando un file environment.js che può essere usato per rilevare i canali di rilascio expo e modificare le variabili restituite in base a quello, ma per la costruzione, ho bisogno di aggiornare la variabile non DEV restituita per essere in staging o prod:

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;

alternative

qualcuno ha esperienza nell'uso di reagire-nativo-dotenv per progetti realizzati con Expo? Mi piacerebbe sentire i tuoi pensieri

https://github.com/zetachang/react-native-dotenv


È possibile definire tutti i nomi dei canali di rilascio desiderati e testare il nome per definire la variabile di ambiente. Dove vedo la limitazione è nell'ambiente di sviluppo in cui releaseChannel non è definito. Quindi forse potresti usare babel-plugin-transform-inline-environment-variabili - potresti trasmettere variabili d'ambiente nei tuoi script e fare riferimento a process.env ['VAR_NAME'] nel tuo file environment.js se dev?
Colemerrick,

0

puoi anche avere diversi script env: production.env.sh development.env.sh production.env.sh

E poi procurateli quando iniziano a lavorare [che è appena legato ad un alias] in modo che tutto il file sh abbia sia esportato per ogni variabile env:

export SOME_VAR=1234
export SOME_OTHER=abc

E quindi l'aggiunta di variabili di ambiente babel-plugin-transform-inline-environment consentirà di accedervi nel codice:

export const SOME_VAR: ?string = process.env.SOME_VAR;
export const SOME_OTHER: ?string = process.env.SOME_OTHER;

Stai aggiungendo qualcosa che @chapinkapa non ha detto?
Maximo Dominguez,

0

La risposta di chapinkapa è buona. Un approccio che ho adottato dal momento che Mobile Center non supporta le variabili di ambiente è quello di esporre la configurazione di build tramite un modulo nativo:

Su 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;
    } 

o su 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]
  }

Puoi leggere la configurazione della build in modo sincrono e decidere in Javascript come ti comporterai.


0

È possibile accedere alle variabili con process.env.blablainvece di process.env['blabla']. Di recente l'ho fatto funzionare e ho commentato come l'ho fatto su un problema su GitHub perché avevo alcuni problemi con la cache in base alla risposta accettata. Ecco il problema.


Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.