はじめに
で API Key を暫定的にソースコードに含めていました。
// ...
class RakutenAPI {
static const String apiKey = '[API Key]'; // 取得したAPIキーをここに入れる
// ...
これだと、APIキーをコミットしてしまうリスクがあるため、環境変数化する方法を検討していきます。
環境変数化について
アプリケーションの開発では、環境ごと(開発、ステージング、本番など)に異なる値はソースには直接記載せず、外部から取得する仕組みが必要になってきます。
Flutterではビルドしたパッケージを端末にインストールする特性上、以下の2つの方法を使うことができます。
環境変数をファイルとしてパッケージに含め、必要に応じて読み込む
flutter_dotenv
が有名なようです。
flutter_dotenv
は、.env
ファイルから環境変数を読み込むためのライブラリです。このライブラリを使用すると、アプリケーション内で簡単に設定値を利用できます。
ビルド時に環境変数を渡してバイナリに含める
--dart-define
や --dart-define-from-file
といったオプションをビルドコマンドで指定することで、環境変数を渡すことができます。
渡された環境変数はコード上に埋め込まれ、バイナリに含まれます。
以前は、--dart-define
で1つずつパラメータを渡す必要がありましたが、Flutter 3.7 からは --dart-define-from-file
を使ってファイルで渡せるようになりました。
方式検討
flutter_dotenv
と --dart-define-from-file
を比較し、 --dart-define-from-file
を採用することにしました。
ここではその詳細を記載します。
1. flutter_dotenv
flutter_dotenv
は、Flutterプロジェクトで .env
ファイルを読み込むためのライブラリです。他のプラットフォームでもよく使われる方法なので、直感的でわかりやすい反面、幾つかデメリットがあります。
メリット
-
セットアップが容易
-
.env
ファイルを作成し、ライブラリを追加するだけ
-
-
柔軟な環境変数の管理
- 実行時に動的に環境変数を読み取ることができる
デメリット
-
コードがライブラリに依存する
-
flutter_dotenv
ライブラリを導入する必要があり、起動時の.env
ファイル読み込み処理を入れる必要があります。また、使用時にもライブラリを使って環境変数を取得する必要があります
-
-
.env
ファイルが パッケージに plain text で含まれる-
.env
ファイルの中身がアプリケーションパッケージにそのまま含まれるため、容易に値を取り出せてしまいます
-
-
pubspec.yaml
で asset として明示する必要がある-
.env
ファイルをpubspec.yaml
に記載しなければならず、必ず.env
ファイルを作成する必要があります。存在しない場合、アプリの起動に失敗します
-
2. --dart-define-from-file
Flutterの公式機能である --dart-define-from-file
を使用する方法です。オプションで指定しないといけないデメリットはあるものの、 flutter_dotenv
のデメリットを回避することができます。
メリット
-
ライブラリへの依存が不要
- オプションを指定するだけなので、ライブラリの導入や明示的な読み込み処理の追加が不要です
- 利用時も以下のような標準的な方法で値を取得することができます
static const String apiKey = String.fromEnvironment('RAKUTEN_API_KEY');
-
値がバイナリとして含まれる
- 環境変数はバイナリとしてアプリに埋め込まれるため、plain textと比べて読み取りが困難です
- ※ ただし、暗号化されるわけではないため、機密情報は含めないように注意が必要
-
環境ごとの切り替えが容易
- 使用する
.env
ファイルをビルド時に指定するだけで、環境ごとの設定を簡単に切り替えることができます
- 使用する
デメリット
-
設定の手間
- ビルドコマンドで指定しないといけないため、ビルド時やローカル起動時などは起動設定を入れる必要があります
-
ランタイムでの変更が不可
- アプリ起動後に環境変数を変更することができません
結論
flutter_dotenv
を使う場合、ライブラリに依存してしまうのと、asset として .env
ファイルを含める必要があるデメリットが大きいため、--dart-define-from-file
を使うことにしました。
使用例
実際に --dart-define-from-file
を使用した環境変数の管理方法を実装していきます。
.env
ファイルの作成
RAKUTEN_API_KEY=1234567890123456789
起動設定に追加
コマンド実行
# 起動(macos)
flutter run -d macos --dart-define-from-file=.env
# ビルド(macos)
flutter build macos --dart-define-from-file=.env
VSCodeの起動設定を修正
起動設定 (launch.json
) にオプションを追加します。
{
"version": "0.2.0",
"configurations": [
{
"name": "Flutter",
"type": "dart",
"request": "launch",
- "program": "lib/main.dart"
+ "program": "lib/main.dart",
+ "args": [
+ "--dart-define-from-file=.env"
+ ]
}
]
}
コード内で環境変数の取得
冒頭の楽天APIを例に修正してみます。
// ...
class RakutenAPI {
- static const String apiKey = '[API Key]'; // 取得したAPIキーをここに入れる
+ static const String apiKey = String.fromEnvironment('RAKUTEN_API_KEY');
// ...
.gitignore
に .env
を追加
誤って環境依存の値を commit してしまわないように除外設定を追加しておきます。
+ # local environment file
+ .env
まとめ
--dart-define-from-file
を使うと、ライブラリへの依存を避けつつ、環境依存値を外部に抜き出してみました。
少し調べると、ios ビルド時そのままだと --dart-define-from-file
で指定した値が読み込まれない不具合があるようですので、別途見ていきたいと思います。
(iOS での Debug起動時は使えていたので、リリース時の問題か、修正済みなのかも...?)