flutterのdart-defineは2.2以上ではbase64でエンコードされるので対応したスクリプトの紹介

こんにちは。[もぐめっと](https://mogmet.com)です。

![mogmet.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42234/d9c1a4d0-8366-9cb9-b7cc-215f47183d73.jpeg)

ホテルにいたお馬さんが気になりすぎて、ついけつに指差しちゃいました。

最近flutterをいじっていてFlutterアップデートによる罠を受けましたので共有いたします。

みなさんdart-defineはご存知ですか？
dart-defineを使うと環境ごとに設定ファイルなどを切り替えることができます。

具体的な手順に関しては下記記事が参考になります。

https://zenn.dev/kingu/articles/9192b91062841b8e0bba


https://qiita.com/tetsufe/items/3f2257ac12f812d3f2d6

今回は上記の手順ではFlutter1.17までの方法しか記載されていなかったのですが、下記記事でFlutter2.2からの手順もあったためdart-defineのアップデートに関する部分だけ抜粋して紹介します。

https://itnext.io/flutter-1-17-no-more-flavors-no-more-ios-schemas-command-argument-that-solves-everything-8b145ed4285d

## dart-defineの表現歴史

dart-defineの歴史は下記の通りに変わってきました。

- Flutter1.17~: すべてのDartDefineをカンマで結合された単一の文字列値として渡します

```
DEFINEEXAMPLE_APP_NAME=awesomeApp1,DEFINEEXAMPLE_APP_SUFFIX=.dev
```

- Flutter 1.20~: コンパイラに渡される前にURIシンボルをエンコードします

```
DEFINEEXAMPLE_APP_NAME%3Dawesome1,DEFINEEXAMPLE_APP_SUFFIX%3D.dev
```

- Flutter 2.2~: 各変数はbase64でエンコードされます

```
REVGSU5FRVhBTVBMRV9BUFBfTkFNRT1hd2Vzb21lMg==,REVGSU5FRVhBTVBMRV9BUFBfU1VGRklYPS5kZXY=
```

## スクリプト

表現方法の変更に合わせてandroidのgradleやiosのpre build scriptなども変更しないといけなくなりました。
（これらのスクリプトの使い方は冒頭に紹介した記事をご参考ください！）

### Android (gradle)

```flutter1.17.gradle
def dartEnvironmentVariables = [
    DEFINEEXAMPLE_APP_NAME: 'awesomeApp',
    DEFINEEXAMPLE_APP_SUFFIX: null
];
if (project.hasProperty('dart-defines')) {
    dartEnvironmentVariables = dartEnvironmentVariables + project.property('dart-defines')
        .split(',')
        .collectEntries { entry ->
            def pair = entry.split('=')
            [(pair.first()): pair.last()]
        }
}
```

```Flutter1.20.gradle
if (project.hasProperty('dart-defines')) {
    dartEnvironmentVariables = dartEnvironmentVariables + project.property('dart-defines')
        .split(',')
        .collectEntries { entry ->
            def pair = URLDecoder.decode(entry).split('=')
            [(pair.first()): pair.last()]
        }
}
```

```Flutter2.2.gradle
if (project.hasProperty('dart-defines')) {
    dartEnvironmentVariables = dartEnvironmentVariables + project.property('dart-defines')
            .split(',')
            .collectEntries { entry ->
                def pair = new String(entry.decodeBase64(), 'UTF-8').split('=')
                [(pair.first()): pair.last()]
            }
}
```

### iOS

```Flutter1.17.sh
echo "$DART_DEFINES" | tr ',' '\n' > ${SRCROOT}/Flutter/Defineexample.xcconfig
```

```Flutter1.20.sh
function urldecode() { : "${*//+/ }"; echo "${_//%/\\x}"; }

IFS=',' read -r -a define_items <<< "$DART_DEFINES"

for index in "${!define_items[@]}"
do
    define_items[$index]=$(urldecode "${define_items[$index]}");
done

printf "%s\n" "${define_items[@]}"|grep '^DEFINEEXAMPLE_' > ${SRCROOT}/Flutter/Defineexample.xcconfig
```

```Flutter2.2.sh
function entry_decode() { echo "${*}" | base64 --decode; }

IFS=',' read -r -a define_items <<< "$DART_DEFINES"


for index in "${!define_items[@]}"
do
    define_items[$index]=$(entry_decode "${define_items[$index]}");
done

printf "%s\n" "${define_items[@]}"|grep '^DEFINEEXAMPLE_' > ${SRCROOT}/Flutter/Defineexample.xcconfig
```

## まとめ

Flutterのバージョンに合わせてスクリプトを修正する必要があるのでdart-defineを使う場合は注意しましょう。

最後に、[ワンナイト人狼オンライン](https://online.1nite-jinro.com/link/blog)というゲームを作ってます！よかったら遊んでね！

https://online.1nite-jinro.com/link/blog

他にも[Camecon](https://camecon.me/)や[Offcha](https://offcha.com/)といったサービスも作ってるのでよかったら使ってね！

https://camecon.me/

https://offcha.com/

また、チームビルディングや技術顧問、Firebaseの設計やアドバイスといったお話も受け付けてますので御用の方は弊社までお問い合わせください。

https://virapture.com/