Know-how アプリ開発 読了目安 約6分

アプリのバージョン番号とビルド番号の付け方|Flutterでの管理とストア申請時のエラー対策

アプリをストアに出し直そうとしたら「このバージョンコードはすでに使用されています」と弾かれた。個人開発でとてもよくあるつまずきです。バージョン番号とビルド番号の違いを押さえておくと、申請のたびに迷わずに済みます。

番号は2種類ある

アプリには、役割の違う2つの番号があります。

バージョン番号ビルド番号
例1.2.345
誰のための番号か利用者(ストアの画面に表示される)ストアとOS(更新の判定に使う)
Androidでの名前versionNameversionCode
iOSでの名前CFBundleShortVersionStringCFBundleVersion
決まり形式は自由(慣例は「x.y.z」)アップロードのたびに大きくする

利用者が目にするのはバージョン番号ですが、ストアが「新しいファイルかどうか」を判断するのはビルド番号です。ストアへのアップロードで弾かれる原因は、ほとんどがビルド番号のほうです。

Flutterでは pubspec.yaml の1行で管理する

Flutterでは、pubspec.yaml の version に、2つの番号を + でつないで書きます。

version: 1.2.3+45

+ の前の 1.2.3 がバージョン番号、後ろの 45 がビルド番号です。ビルドすると、この値がAndroidとiOSの両方に自動で反映されます。

Android側の受け取り方

android/app/build.gradle.kts の defaultConfig に、次のように書かれていれば、pubspec.yamlの値が使われます。

defaultConfig {
    // (applicationId などは既存のまま)
    versionCode = flutter.versionCode
    versionName = flutter.versionName
}

iOS側の受け取り方

ios/Runner/Info.plist では、次のように変数で受け取っています。

<key>CFBundleShortVersionString</key>
<string>$(FLUTTER_BUILD_NAME)</string>
<key>CFBundleVersion</key>
<string>$(FLUTTER_BUILD_NUMBER)</string>

どちらかに数字が直接書かれていると、pubspec.yamlを変えても反映されません。Xcodeの「General」タブでVersionやBuildを手で書き換えると、ここが数字に置き換わってしまうことがあるので注意してください。番号は必ずpubspec.yaml側で変える、と決めておくと混乱しません。

ビルド番号のルール

Android(Google Play)

  • versionCode は整数で、アップロードするたびに前より大きくする必要があります。
  • 一度アップロードした番号は、内部テスト用でも、公開しなかったものでも、二度と使えません。
  • 上限は2100000000です。

同じ番号でアップロードすると、Play Consoleで「バージョンコード 45 はすでに使用されています。別のバージョンコードをお試しください。」という趣旨のエラーが出ます。

iOS(App Store Connect)

  • 同じバージョン番号の中では、ビルド番号を前より大きくする必要があります。
  • TestFlightに上げただけのビルドの番号も、使用済みになります。

違反すると、アップロード時に「The bundle version must be higher than the previously uploaded version.」というエラーになります。

iOSはバージョン番号が変われば番号を1から数え直すこともできますが、AndroidとiOSで考え方を分けるとややこしくなります。ビルド番号は両OS共通で、アップロードのたびに1ずつ増やし続けるのが、個人開発ではいちばん簡単で安全です。

バージョン番号の上げ方の目安

バージョン番号に厳密なルールはありませんが、「メジャー.マイナー.パッチ」の3つに分ける書き方(セマンティックバージョニング)が広く使われています。アプリなら、次くらいの感覚で十分です。

上げる数字どんなとき例
メジャー(1つ目)見た目や使い方が大きく変わる1.4.2 → 2.0.0
マイナー(2つ目)新しい機能を追加した1.4.2 → 1.5.0
パッチ(3つ目)不具合の修正だけ1.4.2 → 1.4.3

同じバージョン番号のまま、ビルド番号だけを上げて出し直すこともできます。審査で修正を求められて提出し直す場合などは、バージョン番号はそのままで、ビルド番号だけを増やします。

コマンドで一時的に上書きする

pubspec.yamlを書き換えずに、ビルド時に番号を指定することもできます。

flutter build appbundle --build-name=1.2.3 --build-number=46
flutter build ipa --build-name=1.2.3 --build-number=46

自動ビルドの仕組みを作るときには便利ですが、手作業でリリースする場合は、pubspec.yamlを正として毎回書き換えるほうが、あとから「どの番号で出したか」を追いやすくなります。

Xcodeからアーカイブするときの注意

iOSでよくあるのが、「pubspec.yamlの番号を上げたのに、Xcodeでアーカイブしたら古い番号のままだった」というケースです。

Flutterは、ビルドのときに ios/Flutter/Generated.xcconfig というファイルに番号を書き出し、Xcodeはそれを読みます。pubspec.yamlを変えたあと、Flutterのコマンドを一度も実行せずにXcodeでアーカイブすると、このファイルが古いままなのです。

対策は簡単で、Xcodeでアーカイブする前に、ターミナルで次のどちらかを実行しておきます。

flutter build ipa
# または
flutter build ios --release

flutter build ipa なら、アーカイブとアップロード用ファイルの作成まで行われるので、Xcodeを開かずに済むこともあります。

アプリの中に番号を表示する

設定画面などにバージョン番号を表示しておくと、問い合わせを受けたときに「どの版で起きた不具合か」がすぐ分かります。package_info_plus パッケージを使うと、実行中のアプリの番号を取得できます。

import 'package:package_info_plus/package_info_plus.dart';

Future<String> versionLabel() async {
  final info = await PackageInfo.fromPlatform();
  return 'バージョン ${info.version}(${info.buildNumber})';
}

番号を手で書いた文字列を表示していると、更新のたびに書き換え忘れが起きます。実際の値を取得して表示するほうが確実です。

リリース前のチェックリスト

  1. pubspec.yamlのビルド番号を、前回アップロードした番号より大きくした。
  2. 新機能や修正の内容に合わせて、バージョン番号を上げた。
  3. Info.plistとbuild.gradle.ktsが、pubspec.yamlの値を参照している。
  4. iOSは flutter build ipa(または flutter build ios)を実行してからアーカイブした。
  5. リリースした番号と日付、変更内容をメモした。

最後のメモは地味ですが、あとで役に立ちます。ストアの「新機能」欄に書いた文章と一緒に残しておくと、次のリリースのときの下書きにもなります。