反応ネイティブで環境変数を設定しますか?


152

反応ネイティブを使用してクロスプラットフォームアプリを構築していますが、環境変数を設定する方法がわからないため、環境ごとに異なる定数を使用できます。

例:

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

これを試すことができますimport {Platform} from 'react-native'; console.log(Platform);
Praveen Prasad

回答:


138

アプリの定数をハードコーディングして環境を切り替える(代わりにその方法を説明します)代わりに、ビルドプロセスでとを定義するという12要素の提案を使用することをお勧めし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)によってリアクションネイティブコードをトランスパイルする場合は、次のようなコードを作成するだけです。

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

そして、Babelは次のものに置き換えます。

const apiKey = 'my-app-id';

お役に立てれば!


7
すばらしい解決策のように聞こえますが、RN @ 0.37.0では私にはうまくいきません。唯一のプロパティはprocess.envですNODE_ENV
アダムファリーナ2017

2
Jack Zhengによる以下の回答を参照してください...を介して変数にアクセスできませんprocess.env.API_KEY... process.env['API_KEY']代わりに使用してください
Steven Yap

6
未定義としてprocess.env ['API_KEY']を取得しています。私は、この設定することができます誰も助け
user1106888

2
私は同じ問題を抱えていました:未定義
Guto Marrara Marzagao

7
v0.56で動作します。react-native start --reset-cache環境変数を変更するたびに実行して、バンドルのキャッシュをクリアする必要があります。
soheilpro

55

私が見つけた最も簡単な(最善で理想的でもない)ソリューションは、react-native-dotenvを使用することでした。次の.babelrcように、プロジェクトルートのファイルに"react-native-dotenv"プリセットを追加するだけです。

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

.envファイルを作成し、プロパティを追加します。

echo "SOMETHING=anything" > .env

次に、プロジェクト(JS)で:

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

1
私は.envベースのソリューションを望んでいました。ありがとうございました!
Anshul Koka 2017

3
@Slavo Vojacekどのように私は例のいずれかに設定するには、これを使用するかbase_url、両方のためにstagingproduction
Compaq LE2202x 2018

@ CompaqLE2202x私が理解していることはよくわかりませんか?.env(環境ごとに)異なるファイルを使用すること、または異なるファイルで値の一部を再利用することについて.env質問していますか?
Slavo Vojacek

5
@SlavoVojacek私は別について聞いてるのよ.env環境ごとのファイル聞かせてのは、言うstagingproduction
Compaq LE2202x 2018年

@SlavoVojacekは、CIステージまたはデプロイメントで値を上書きできませんでしたか?
mgamsjager

37

私の意見では、最良のオプションはreact-native-configを使用することです。12要素をサポートしています。

このパッケージは非常に便利だと思いました。開発、ステージング、本番など、複数の環境を設定できます。

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

9
READMEには、このモジュールはパッケージ化のための秘密を難読化または暗号化しないため、.envに機密キーを保存しないことに注意してください。ユーザーがモバイルアプリのシークレットをリバースエンジニアリングできないようにすることは基本的に不可能です。そのため、アプリ(およびAPI)を設計してください
Marklar

ツイッターのように、.envでキーをcom.twitter.sdk.android.CONSUMER_KEYとして設定する必要がある一部のフレームワークでは機能しません
thibaut noah

マニフェスト内にキーを配置する場合、拡張機能がそれをサポートします。この回答では説明されていません。XML、Java、JSファイルで変数を使用できます。
sfratini、2017年

4
react-native-configはRN 0.56では機能せず、未解決の問題があり、6か月以上メンテナンスされません。魔女がRNでの使用を停止する問題はgithub.com/luggit/react-native-config/issues/267です。これを動作させるためのハッキングをいくつか示しますgithub.com/luggit/react-native-config/issues/285
Marecky

24

Reactネイティブには、グローバル変数の概念がありません。これは、強制モジュラースコープを部品モジュール性と再利用性を促進するために、厳密に。

ただし、場合によっては、コンポーネントの環境を認識する必要があります。この場合、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

これにより、アプリのスコープ内のどこからでもアクセスできるシングルトン環境が作成されます。require(...)環境変数を使用するコンポーネントからモジュールを明示的に指定する必要がありますが、それは良いことです。


19
私の問題はどのようにgetPlatform()。私はこのようなファイルを作成する必要がありますが、ここでのロジックを終えることができないネイティブに反応
デイモン元

@DamonYuanは、パッケージの設定方法に完全に依存します。それはあなたの環境に依存しているので、私はそれが何を意味し、何を意味するstagingproductionさえわかりません。たとえば、IOSとAndroidで異なるフレーバーが必要な場合は、環境を初期化することができます。index.ios.jsそれに環境とindex.android.jsファイルをインポートし、そこにプラットフォームを設定しますEnvironment.initialize('android')
トースター

@DamonYuanは私が助けにしたことを何でもしますか、それともいくつかの説明が必要ですか?
chapinkapa

これは、コードを制御できる場合に非常に便利です。process.envに依存する3番目の部分のモジュールを実行しているので、...
enapupe

2
env.jsファイルを作成する場合は、チェックインからリポジトリへのファイルを無視し、使用したキーを空の文字列値とともに別のenv.js.exampleファイルにコピーして、他の人がより簡単にアプリを構築できるようにしてください。プロジェクトシークレットを誤ってチェックインした場合は、履歴書き換えて、ソースだけでなく履歴からも削除することを検討してください。
Josh Habdas

17

__DEV__この問題を解決するために、react-nativeに組み込まれているポリフィルを使用しました。true本番用にネイティブのリアクションをビルドしていない限り、自動的にに設定されます。

例えば:

//vars.js

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

export {url, publicKey}

それからちょうどimport {url} from '../vars'あなたは常に正しいものを取得します。残念ながら、これは3つ以上の環境が必要な場合は機能しませんが、簡単で、プロジェクトに依存関係を追加する必要はありません。


xcodeでリリースビルドを作成する場合でも、DEVをTRUE に「絞り込む」方法を知っていますか?
realtebo 2018

1
いいえ。開発変数を使用してリリースビルドを実行する場合は、prod varsをコメントアウトし、dev varsをprodセクションにコピーして貼り付けます。
Logister

1
私はこれが最もエレガントな解決策だと
思った

5

環境変数の設定に使用される特定の方法は、CIサービス、ビルドアプローチ、プラットフォーム、および使用しているツールによって異なります。

CIでBuddybuildを使用してアプリを構築し、環境変数管理していて、JSからconfigにアクセスする必要がある場合env.js.exampleは、ソース管理にチェックインするためのwithキー(空の文字列値)を作成し、Buddybuildを使用してステップのenv.jsビルド時にファイルを作成しpost-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

ヒント:設定とシークレットが開発中に誤ってソース管理にチェックインされないように、追加env.jsする.gitignoreことを忘れないでください。

その後、使用して、ファイルが書き込まれますどのように管理することができBuddybuild変数を同様にBUDDYBUILD_VARIANTSあなたの設定はビルド時に生成される方法をより細かく制御を得るために、例えば、。


全体的に私はアイデアが好きenv.js.exampleですが、パーツはどのように機能しますか?ローカル環境でアプリを起動したいとしましょう。私のenv.jsファイルがgitignoreにありenv.js.example、アウトラインとして使用されている場合、これenv.js.exampleは正当なJS拡張機能ではないため、この部分の意図が少し混乱しています
volk

@volk env.js.exampleファイルは参照ドキュメントとしてコードベースにあります。これは、アプリが使用する必要のある構成キーに関する正規の情報源です。どちらも、アプリの実行に必要なキーと、コピーして名前を変更すると予想されるファイル名について説明しています。このパターンは、dotenv gemを使用するRubyアプリでは一般的です。ここからパターンを取り出しました。
Josh Habdas 16

3

次のライブラリのようなものが、パズルの欠けている部分である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


3
言及されていない代替アプローチを提供することに賛成。1つのサイズですべてに対応することはできません。
Josh Habdas

非同期プル要求がマージされました
jcollum

5
react-native-envはAndroidをサポートしていないようです。ポイントは何ですか?
jcollum

3

異なる環境にいくつかの異なる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を実行するカスタムを作成しました

私のpackage-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)

3

ステップ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

2

使用します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

各envファイル:

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']NOT を使用するprocess.env.STRING必要があります。そうしないと、正しく変換されません。


REMEMBER you have to use process.env['STRING'] NOT process.env.STRING or it won't convert properly.ありがとう!これは私をつまずくものです!!!
Steven Yap

1

[ソース]私が見つけたものから、それはデフォルトでのように見えます、それは本番および開発構成のみを実行することが可能です(ステージングまたは他の環境ではありません)–それは正しいですか?

現在、expoリリースチャネルを検出し、それに基づいて返される変数を変更するために使用できるenvironment.jsファイルを使用していますが、ビルドするために、返される非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を使用した経験はありますか?私はあなたの考えを聞きたいです

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


必要な数のリリースチャネル名を定義し、その名前をテストして環境変数を定義できます。制限があるのは、releaseChannelが定義されていない開発環境の場合です。だから多分あなたはbabel-plugin-transform-inline-environment-variablesを使うことができます-もしあなたがあなたのスクリプトで環境変数を渡して、もしdev。
colemerrick

0

別の環境スクリプトを使用することもできます。production.env.shdevelopment.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;

@chapinkapaが言っていない何かを追加しますか?
Maximo Dominguez 2017

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

process.env.blabla代わりにで変数にアクセスできますprocess.env['blabla']。私は最近それを動作させ、GitHubの問題でそれをどのように実行したかについてコメントしました。受け入れられた回答に基づいてキャッシュに問題があったためです。ここに問題があります。


弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.