Flutterでpubspec.yamlのversionだけ切り替える方法
はじめに
こんにちは。Flutterアプリ開発している@kazy_developerです。
Qiitaでの投稿ばかりでしたが初めてZennでの記事となります。
関わっているFlutterプロジェクトで1プロジェクトでソースコードがほぼ同じ2つのアプリを管理することがあったので、今回はそれらのpubspec.yaml
のversion
を分ける方法について書きます。
稀かもしれませんが、こういったケースとしては、
無料と有料でアプリを分けるケースや、一部機能だけをアプリ別で切り分けるといった場合でしょうか。
そのような1プロジェクトでソースコードがほぼ同じ2つのアプリを管理する場合、
当然それぞれのアプリごとにpubspec.yaml
のversion
が変わる...というより変えるはずです。
また、それぞれのアプリで接続環境が異なる場合は
さらに、App1
、App2
のそれぞれでDebug
、Staging
、Release
のような複数のビルド環境が存在し、その環境ごとにバージョンを変えるといった場合もあるかもしれませんね。
環境を分ける方法
直接的に関係ありませんが、今回は--dart-defineやFlavorでの環境分けをしている前提で記載します。
Flutterで環境を分ける方法は色々ありますが、
詳しい環境分けについては以下の記事が大変参考になりますのでおすすめです。
本題に進みます。
pubspec.yaml内のバージョンを切り分ける方法
バージョンを切り分ける方法はいくつかありそうで、ざっと思いつくのは以下です。
1. ブランチをバージョン別で切り分ける
2. pubspec.yaml自体を環境別もしくはバージョンごとに分ける
3. pubspec.yaml内のversion行だけscriptで書き換える
1. ブランチをバージョン別で切り分ける
これは一番手っ取り早くわかりやすく難易度低めの方法。
いちいち細かな設定をプロジェクトに入れる必要はなく、一番簡単で楽な運用方法です。
ただ、ブランチが増える上、都度切り替える必要がありますし、
App1
のブランチにいる状態でその同一ブランチ内でApp2
をbuild/runするとなると、手動でバージョンを書き換える必要ができてきます。
動作確認の際にバージョンがどんな値でも問題なければそれでも良いですが、
例えば、
・Firebase RemoteConfig
などでバージョン管理をしている
・バージョンがその設定値未満であれば強制アップデートダイアログを表示
・その場合はアプリをいじることができない
という実装が施されていると仮定してみます。
以下のような状態。
pubspec.yaml
に記載のバージョンが3.0.0
の状態で、
RemoteConfig
で設定しているApp1
の最低バージョンが3.0.0
RemoteConfig
で設定しているApp2
の最低バージョンが1.0.0
現在、App1
ブランチにいる状態で、App2
の動作確認をするとなった時、
そのままビルドするとアウトなので、手動で3.0.0以上
に変えるかApp2
ブランチに移動する必要がででしまいます。
これぐらいであればブランチ切り替えせず、手動version
変更でも実害はなさそうですが、そもそも変更する手間はかかってしまいます。
また、APIごとにサーバ側でアプリのバージョン管理していて、特定のバージョンからのリクエストは受付ないもしくは、レスポンスの中身が変わるなどあるならなおのこと頻繁には触りたくないものです。
2. pubspec.yamlを環境別もしくはバージョンごとに分ける
次にpubspec.yaml
ごと分ける方法。
project配下に環境別もしくはバージョン別に
pubspec_app1.yaml
pubspec_app2.yaml
を用意しておいて、run/build前にscriptでpubspec.yaml
に上書きする方法です。
iOSだとFirebaseのinfo.plistを環境別に差し替えたりする時にやるのと同じような感じ。
アプリや環境ごとにパッケージやプラグインがかなり違う、もしくは、それらの依存周りでパッケージバージョンを分ける必要があるケースならこれもあり。
でも今回はアプリのバージョンを変えたいだけなので微妙です。
3. pubspec.yaml内のversion行だけscriptで書き換える
というわけで今回の本題であるpubspec.yaml
内の特定行の書き換えです。
ブランチ運用でも良いのですが、ブランチが増えるしマージコミット祭りになるのでこれに落ち着きそうです。
普通に考えて、アプリごとや環境別にversion
だけ書き変わってくれれば要件は満たせますので、これを進めていきます。
pubspec.yamlのversionを置き換えるshell script
まず実際に置き換える為のscript
をproject
のpubspec.yaml
と同階層に作っておきます。
#!/bin/sh
APP1_VERSION="3.0.0+1"
APP2_VERSION="1.0.0+1"
version=$(grep "version:" pubspec.yaml | awk '{print $2}')
current_flavor=$1
if [ "${current_flavor}" == "app1Development" ] || [ "${current_flavor}" == "app1Staging" ] || [ "${current_flavor}" == "app1Production" ]; then
version="${APP1_VERSION}"
elif [ "${current_flavor}" == "app2Development" ] || [ "${current_flavor}" == "app2Staging" ] || [ "${current_flavor}" == "app2Production" ]; then
version="${APP2_VERSION}"
fi
sed -i '' "s/version:.*/version: ${version}/" pubspec.yaml
実際に叩く時は、Flavorの値を流し込んで判定させます。
./version.sh {Flavorの値}
設定方法
全部コマンド完結するなら後述するようにmakefile
などでまとめて実行させていやれば問題ないと思います。
しかし僕の場合、基本的に動作確認の際はAndroid StudioのGUI右上のRun/Debugボタン
から実行する頻度が多めです。
コマンドでflutter run
を実行するのは稀ですが、aab
、apk
やipa
を生成する時には、コマンドでflutter build
を叩きます。
(こっちの人が大半じゃないかなとは思います)
なので、
・buildはコマンドからmakefile
経由で実行
・runはRun/Debug Configurations
をいじる
というやり方でいきます。
(もっと良い方法もあると思いますが)
Run/Debug Configurationsの設定
元々あるRun/Debug Configurations
はこんな感じでアプリと環境別の設定を追加していて、
コマンドじゃなくてGUIでRunする場合スクリプトは
Edit Configurations
> Run/Debug Configurations
を開いて
上記の赤枠のようにShell Script
とBefore launch
を追加する必要があります。
ではShell Script
を追加していきます。
左上の+を押して、Shell Script
をクリック
上記のように設定しておきます。
また、Working directory
はプロジェクトのルートを指定しておきます。
これを必要分追加したらFlutterのBuildConfiguraionに戻ってBefore launch
を設定します。
上記のようにBefore launchの+を押して、環境の数だけRun Another Configuration
から先ほど作成したShell Script
を選択して紐づけておけば完了です。
今後のアプリのversion
はversion.sh
内の値を変更して運用するようにします。
これでGUIでのRun/Debug
でも環境別でverision
の切り替えができるようになりました。
build用のmakefile設定
buildのほうは、今回はmakefile使って
buildApp1Release:
./version.sh app1Production
fvm flutter build appbundle --release --flavor app1Production --dart-define=FLAVOR=app1Production
buildApp2Release:
./version.sh app2Production
fvm flutter build appbundle --release --flavor app2Production --dart-define=FLAVOR=app2Production
みたいな感じで書いておけば良いのかなと思います。
最後に
今回の方法以外にも、ネイティブ側をいじる等、様々なやり方があると思いますが、pubspec.yaml
で一元管理したいのでそれらはあまり調べていません。
また、flutter build
の引数に--build-name
と--build-number
つければ上書きできますが、
これらはflutter run
では使えなかったので断念しました。
(もしかしたらできる方法があるのかもですが)
これはベストプラクティスなのかと言われるとわかりませんし、
他に良いやり方があれば変えようと思いますが、ひとまずはこれで落ち着きそうです。
Discussion