dart-defines-from-fileがFlutter3.19以降で使えないとお嘆きの貴兄へ
Flutterのビルドオプションに dart-defines-from-file
というものがあります。JSON形式で環境変数をセットしておくと、Dartはもちろんのこと、AndroidやiOSのネイティブまで自動的に環境変数がセットされるというナイスな機構。Flavor
による開発・検証・本番の切り分けがシンプルでした。
しかし、Flutter3.19から、ネイティブに自動で環境変数が渡るコマンドが削除され、環境の切り替えができなくなってしまいました。正確には、dart-defines-from-file
でセットした変数名がネイティブでビルドする時に連携されなくなった。XCodeで($AAA)
とか書いていた変数が認識されません。
調べたところ、ちょっとした改修で今まで通りdart-defines-from-file
が使えたので、共有します。
dart-defines-from-fileというオプションは削除されていないので、今まで通り利用できます。
iOSの設定
dart-defines-from-file
で設定したJSONは、BASE64でエンコードされDART_DEFINES
というコマンドライン引数として、各ネイティブのプラットフォームに渡ります。
3.16までは、ios/Flutter/Generated.xcconfig
に、自動的に変数が展開されていました。それが、3.19以降はなくなってしまった。それだけの話。
そのため、Generated.xcconfig
ではない別のファイルを作り、今まで同様に変数を展開してそれを参照してビルドできるようにします。
下記に書いてあるiOSの用の設定と同じことをやります。
ちなみに、上記の環境変数の展開そのものは3.17未満では不要です。Generated.xcconfig
に展開されるものを二重に展開してるだけなので。
DART_DEFINESの中身を展開するシェルを作る
#!/bin/sh
OUTPUT_FILE="${SRCROOT}/Flutter/DartDefine.xcconfig"
: > $OUTPUT_FILE
function decode_url() { echo "${*}" | base64 --decode; }
IFS=',' read -r -a define_items <<<"$DART_DEFINES"
for index in "${!define_items[@]}"
do
item=$(decode_url "${define_items[$index]}")
lowercase_item=$(echo "$item" | tr '[:upper:]' '[:lower:]')
if [[ $lowercase_item != flutter* ]]; then
echo "$item" >> "$OUTPUT_FILE"
fi
done
やってることは、DART_DEFINESで渡ってきた変数(コマンドライン引数)をカンマ区切りで分割し、配列 define_itemsにいれて、1個ずつBASE64でデコードして、aa=bb
形式に1行ずつ書き込んでいるだけです。その内容が、ios/Fltter/DartDefines.xcconfig
に書き込まれます。
flutter
から始まる変数も何個かあって、これを除去しないとこのシェルがこける(base64デコードでコケる)ようなので、除去されています。
Debug.xcconfigとRelease.xcconfigにinclude
#include "DartDefine.xcconfig"
を追加するだけ。
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
#include "Generated.xcconfig"
#include "DartDefine.xcconfig"
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
#include "Generated.xcconfig"
#include "DartDefine.xcconfig"
XCodeのPre Build Scriptに追加
Xcodeで、Product > Scheme > Edit Scheme -> Build -> Pre-actions を選択しして、
「New Run Script Action」です。
「Provide build settings from」は Runner を選択!これが抜けてると環境変数渡らない!
上記で作ったシェルのパスを指定するだけ。${SRCROOT}/scripts/extract_dart_defines.sh
となります。
おわり。
Androidの設定
gradleにDART_DEFINESを展開する関数を追加
def dartEnvironmentVariables = [:];
if (project.hasProperty('dart-defines')) {
dartEnvironmentVariables = dartEnvironmentVariables + project.property('dart-defines')
.split(',')
.collectEntries { entry ->
def pair = new String(entry.decodeBase64(), 'UTF-8').split('=')
pair.size() == 2 ? [(pair.first()): pair.last()] : [:]
}
}
これで、dartEnvironmentVariables
経由でdart-defines-from-file
で渡ってきた変数を参照できます。
こんな感じですね。
applicationIdSuffix dartEnvironmentVariables.APP_ID_SUFFIX
resValue "string", "app_name", dartEnvironmentVariables.APP_NAME
Androidはこれだけでした。
今日、Flutter3.22でも同様の設定で対応できたので、dart-define-from-file
がネックになっていたとしたら上記の変更を入れたら、今まで通りに生きていけるはずです。
Discussion