⤴️

【Flutter】アプリのバージョンニングの自動化方法と運用について考える

2023/09/05に公開

概要

CI/CDを組んでいるとアプリのバージョンも自動化してインクリメントしたくないでしょうか?

Flutterプロジェクトはアプリのバージョン(と内部的なバージョン)の更新はpubspec.yamlに記載されているversionフィールドを

name: flutter_playground
description: A new Flutter project.
publish_to: 'none' 
version: 1.0.0+1 # ←これ

各OS用プロジェクトファイルにデフォルトでそのまま適用してくれる仕組みになってます

各バージョンをCI/CDのワークフローの一部に取り入れる際に自動でインクリメントできないかの手段を考えたいと思います

結論(忙しい人向け)

先に結論です

どちらかというとpackage開発向けですが、cider packageが一番柔軟にアプリバージョンとビルドバージョンをインクリメントまた指定のバージョンにアップデートがしやすいかなと考えてます

前提知識と各バージョンの統一性

pubspec.yamlの versionフィールドはセマンティックバージョンニングで記載します

+の左側,右側で以下のように実行時にデフォルトで参照する仕組みになってます

pubspec.yaml Android(local.properties) Android記述 iOS(Generated.xcconfig) iOS記述
versionName セマンティックバージョニング CFBundleShortVersionString セマンティックバージョニング
versionCode 整数値(最大値 2100000000) CFBundleVersion セマンティックバージョニング(マイナーバージョン以降省略可)

アプリのバージョンはAndroid・iOSと同じ記載方法で統一できますが、内部的に使う各versionCodeとCFBundleVersionで記述方法が異なります

ただ、Apple公式ドキュメントを確認すると

You can also abbreviate the build version by using only one or two integers, where missing integers in the format are interpreted as zeros. For example, 0 specifies 0.0.0, 10 specifies 10.0.0, and 10.5 specifies 10.5.0.

整数として省略できるのでAndroidと同じ整数値として統一した方が管理しやすいと思います
(プロジェクト要件によっては記載したい方法が変わるかもしれないので、管理しやすい一つの例ぐらいでの参考でお願いします🙏)

またAndroidは上限値がドキュメントに記載されていますが、iOSの方は特に公式ドキュメントでは言及されていません

余談レベルとして調べてみると以下サイトより↓

https://pgu.dev/2020/12/16/ios-build-versioning.html

Careful with the length of CFBundleVersion as it has not to exceed 18 characters (including dot separators).

という注意書きがあり18文字以内にするよう何かしらの警告が出るようです?

アプリ実行時に試した際は特に出なかったので、時間あった時にはアップロード時に試してみたいと思います

手段

自分が調べていて現状可能なパッケージも含めて4種類あるかなと思います

  • Flutter CLI
  • 自作シェルスクリプトを用意する
  • pub_version_plus パッケージ
  • cider パッケージ

Flutter CLI

Flutterのbuildコマンドのオプションにそれぞれのバージョン指定オプションが用意されてます

  • --build-name・・・アプリバージョン(versionフィールドだと+左側)
  • --build-number・・・内部的なバージョン(versionフィールドだと+右側)
# 例
$ flutter build ios --build-name=2.0.0 --build-number=3

上記のような形でそれぞれのバージョンを更新できるのですが、pubspec.yamlの更新ではなく

Android → local.properties
iOS → Generated.xcconfig

各プロジェクトファイルで用意される設定値の上書きなので、pubspec.yamlのversionフィールドと統一できなくこの方法で運用するとあとでpubspec.yamlファイルを手動更新するスタイルになるのかなと思います

自作シェルスクリプトを用意する

他手段がない場合はこれを検討してもいいですが、yamlファイルの読み書きが少々めんどくさいので最終手段になるかなと思います。。。

pub_version_plus パッケージ

pubspec.yamlのversionフィールドを更新してくれるパッケージです

https://pub.dev/packages/pub_version_plus

ドキュメントに書いてある通りに <version-type> と書いてある箇所にそれぞれのどのアップデートの仕方か

  • major
  • minor
  • patch
  • build

を指定して記載するとそれに適したバージョンでインクリメントしてくれます

※ 以下使用パッケージバージョン: pub_version_plus 1.1.0

# Before 1.2.1 → After 1.3.0
$ dart pub global run pub_version_plus:main minor

# Before 1.2.1 → After 1.2.2
$ dart pub global run pub_version_plus:main patch

ただ、パッケージ運用の場合は問題ないですが buildの箇所は0としてリセットしてしまいます

アプリ運用の場合は内部的なバージョンは各ストアへアップロードする際に前回より大きい値にしないと弾かれてしまうため、pub_version_plusだとちょっと要件が満たせれないのが惜しいです

cider パッケージ

パッケージ開発向けですが、アプリ開発でも柔軟にバージョニングができるコマンドがいくつか用意されています

https://pub.dev/packages/cider

※ 以下使用パッケージバージョン: cider 0.2.3

直指定の方法

# 例
$ dart pub global run cider version 1.0.1+12

どういうアップデートをするかを指定した自動インクリメントの方法

# 例
$ dart pub global run cider bump minor --bump-build

major, minor, patch, buildに合わせた該当箇所に対する現状の値からインクリメントしつつ

--keep-build will retain the existing build part.
--bump-build will increment the build part (see below).

という内部的なバージョンの扱いをどうするかというオプションコマンドも用意されているので柔軟にアップデートできます

まとめ

プロジェクト状況によっては適切なバージョンニング手法は異なるかもしれませんが、pubspec.yamlのバージョンをAndroid/iOSそれぞれのバージョンへそのまま適用する場合はciderパッケージだと、CI/CDのワークフローの一部に導入しやすいかなと考えてます

何か不適切な内容の記載だったり、別手法も検討できる等あれば気軽にご指摘くださいませ🙏

GitHubで編集を提案

Discussion