[Flutter] 環境設定ファイルを読み取れるようにする
はじめに
アプリ開発をしていて環境設定ファイル(.env
)を用意したくなったことはありませんか?
例えば、google_sign_inを使う時にInfo.plistにREVERSED_CLIENT_ID
を追記する必要があります。
ハードコーディングでもいいかも知れませんが、Flavorを分けていたりすると別ファイルを用意してそこから読み取れるようにした方が便利な場面も多いです。
というわけで、Flutterで環境設定ファイルを用意する方法について考えたので共有しようと思います。
ちなみにこの記事の設定を行ったサンプルはここにおいています。
事前準備
Flavorごとに環境設定ファイルを用意しておきます。
今回はFlavorをdev
, prod
に分け、assets
以下に次のようにファイルを用意しました。
assets
└── env
├── .env.dev
└── .env.prod
.env.dev
ファイルの中身は次のような内容です(必ずkeyとvalueを=で繋ぎ、間にスペースは含まないようにしてください)。
GOOGLE_MAP_API_KEY_ANDROID=xxx
GOOGLE_MAP_API_KEY_IOS=xxx
REVERSED_CLIENT_ID=xxx
また、環境設定ファイルはGitで管理すべきではないため、.gitignore
にも追記しておきましょう。
/assets/env
iOS編
iOSの設定を済ますことで、.env
ファイルの内容を次の箇所で参照できるようになります。
- Info.plist
- AppDelegates.swift
- Flutterツールキット側(.dartファイル内)
処理の概要
次に処理の概要をざっくりと。
アプリビルド時に下記のような処理が自動で行われるように設定していきます。
1. EnvironmentVariables.xcconfig生成
Info.plist内で環境ファイルを参照できるようにするための設定をしていきます。
ios/scripts/generate_env.sh
を作成し、次の内容にします。
#!/bin/sh
OUTPUT_FILE="${SRCROOT}/Flutter/EnvironmentVariables.xcconfig"
function decode_url() { echo "${*}" | base64 --decode; }
: > $OUTPUT_FILE
IFS=',' read -r -a define_items <<< "$DART_DEFINES"
for index in "${!define_items[@]}"
do
item=$(decode_url "${define_items[$index]}")
if [ $(echo $item | grep 'FLAVOR') ] ; then
value=${item#*=}
file="${SRCROOT}/../assets/env/.env.${value}"
while IFS= read -r line || [ -n "$line" ]
do
echo $line >> ${OUTPUT_FILE}
done < "$file"
fi
done
ios/Runner.xcworkspace
を開き、Debug.xcconfig
, Release.xcconfig
に
#include "EnvironmentVariables.xcconfig"
を追記します(この時点ではEnvironmentVariables.xcconfig
は生成されていませんのでエラーが出ますが気にしないでください)。
次に、Product->Scheme->EditSchemeを開き、
- Build->Pre-actionsを選択
- +ボタンからNew Run Script Actionsを選択
-
${SRCROOT}/scripts/generate_env.sh
を記述(Runner指定も忘れずに)
これでアプリのビルド前にEnvironmentVariables.xcconfig
が生成されるようになります。
※もしかするとシェルスクリプトに実行権限を付与しておく必要があるかも知れません。
chmod +x ios/scripts/generate_env.sh
この設定によって、例えばgoogle_sign_inの公式ドキュメントには下記の設定方法が書いていますが、
<array>
<!-- TODO Replace this value: -->
<!-- Copied from GoogleService-Info.plist key REVERSED_CLIENT_ID -->
<string>com.googleusercontent.apps.861823949799-vc35...</string>
</array>
それがこのように環境設定ファイルに記述した値(ここではREVERSED_CLIENT_ID
)を使用できます。
<array>
<!-- TODO Replace this value: -->
<!-- Copied from GoogleService-Info.plist key REVERSED_CLIENT_ID -->
<string>$(REVERSED_CLIENT_ID)</string>
</array>
2. .env生成
続けて、AppDelegates.swiftやFlutter側で環境ファイルを参照できるようにするための設定をしていきます。
XcodeのBuild Phasesに環境設定ファイルをコピーする処理を追加します。
- Runnerを選択
- Build Phasesを選択
- New Run Script Phasesを押下
内容を次のようにします。
ここではフェーズ名をCopy Environment Variables
としました。
これにより、アプリビルド時にプロジェクトのルート直下に.env
が生成されるようになります。
↓コピー用
\cp -f ${SRCROOT}/../assets/env/.env.${FLAVOR} ${SRCROOT}/../.env
次に、AppDelegates.swiftやFlutter側で読み取れるようにします。
flutter_configという便利なパッケージがあるのでそちらを使わせていただきます。
基本的には公式ドキュメント通り設定するだけなので難しくはないと思いますが、表に明記されていない部分もあるため軽く触れておきます。
Flutter側の設定
- パッケージインストール後、main関数内に環境設定ファイル読み込み処理を追記
import 'package:flutter_config/flutter_config.dart';
void main() async {
// 次の2行を追記する
WidgetsFlutterBinding.ensureInitialized();
await FlutterConfig.loadEnvVariables();
runApp(MyApp());
}
このような呼び出しにより値が取得できます。
FlutterConfig.get('REVERSED_CLIENT_ID')
AppDelegates.swiftの設定
AppDelegates.swiftで読み取る方法について、何故か公式ドキュメントには記載がありませんでしたが、Issueにはその方法が書かれていたので紹介しておきます。
↓該当のIssue
AppDelegates.swiftにimport flutter_config
を追記し、次の呼び出しにより環境設定ファイルの値を参照することができます。
FlutterConfigPlugin.env(for: "SOME_KEY_FROM_ENV")
例えば、google_maps_flutterの公式ドキュメントには、次のコードの// 1. の方法が記載されていますが、// 2. のように記述することができるようになります。
import UIKit
import Flutter
import GoogleMaps
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
// 1. 公式ドキュメント通りの方法(キーをハードコーディングする)
GMSServices.provideAPIKey("YOUR KEY HERE")
// 2. 環境設定ファイルから読み取ったキーを使う
GMSServices.provideAPIKey(FlutterConfigPlugin.env(for: "GOOGLE_MAP_API_KEY_IOS"))
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}
Android編
WIP
flutter_config公式のAndroidドキュメントはこちら(https://github.com/ByneappLLC/flutter_config/blob/master/doc/ANDROID.md)。
- GitHubのコード該当箇所
- android/app/build.gradleの↓のコードがpreBuildタスクのタイミングで呼ばれ、assets/.env.${FLAVOR}がルート直下の.envにコピーされる
task selectEnvironmentVariable(type: Copy) {
from "../../assets/env/.env.${dartEnvironmentVariables.FLAVOR}"
into "../../"
rename { name -> ".env" }
}
ここの追加もお忘れなく。
- build.gradleやAndridManifest.xml内でも.envの読み取りはflutter_configに任せてる
Discussion