Open3

Xcode: バージョン番号を自動更新しようとするとビルドが止まる件

kabeyakabeya

Xcodeのプロジェクト→TARGETSで、「General」タブを開くと「Identity」に「Version」と「Build」という番号があります。
このうち「Version」のほうは、手動で更新するべき値ですが、「Build」のほうの番号はビルドのたびに自動更新されるとよいよね、という話です。

(Xcode 14.3です)

今のバージョン番号の仕組み

以前はInfo.plistにこの2つの値を「Version」→「CFBundleShortVersionString」、「Build」→「CFBundleVersion」で記載していたのですが、ふと気付くと、いまこの2つのCFBundleのエントリはなくても「General」タブに値が表示されますし、Archiveするとその「General」タブの番号が表示されますし、そして、App Storeのレビューではじかれることなく登録できます。

自動バージョン番号更新に使えるツール

よくよく調べると、これらの番号は.pbxprojに記録されていて、「Version」→「${MARKETING_VERSION}」、「Build」→「${CURRENT_PROJECT_VERSION}」という値で、ビルド中にスクリプトから参照できます。

それで「Build」のほうは、プロジェクト→TARGETS→「Build Settings」→「Versioning」→「Versioning System」を「Apple Generic」に変更しておくと、

xcrun agvtool next-version

を実行するだけで自動更新させることができます。
ビルドのたびに自動実行させるとよさそうです。

Settingsバンドル

iOSの「設定」アプリに、アプリのバージョン番号やAcknowledgesを載せる、というAppの構成の仕方があります。
Settingsバンドルというものを使うとできます。

https://dev.classmethod.jp/articles/settings-bundle-acknowledgements/

ここのバージョン番号は勝手にあがったりしないので、もしこの構成にするのであれば、都度、書き換える必要があります。これもツールを使って自動で更新されるようにしたいところです。

ツール(スクリプト)の実行可能タイミング

自前のスクリプトを走らせる方法がXcodeのビルドでは3つのタイミングが用意されています。

  1. Productメニュー→Scheme→Edit Scheme...のBuildタグの「Pre-actions」で、左下のプラスボタンを押して「New Run Script Action」を選んで登録
  2. 同じく「Post-actions」で登録
  3. プロジェクトのTARGETS→Build Phasesで、左上のプラスボタンを押して「New Run Script Phase」を選んで登録

1はビルド前、2はビルド後、3はビルド中に実行されます。

3のRun Scriptのフェーズですが、登録直後はビルド中と言いつつも実際はビルドの一番最後に追加されます。
追加後にフェーズごとドラッグ&ドロップすれば、例えばCompile Sourcesの前に持って行く、などもできます。逆に言うと、それをしないとビルドされたAppに更新が反映されてない、ということにもなります。

はまったところ

xcrun agvtool next-versionを、ビルド前またはビルド中に実行されるスクリプトの中に入れると、Xcodeはビルドをやめてしまいます。
何も言わないでこっそりやめます。
エラーで止まるとかでもありませんし、メッセージも出ません。

このためビルド番号の自動更新は、ビルド後に実行する、と割り切ったほうが良さそうです。バージョン管理との兼ね合いにもなると思いますが、そうおかしな話でもないと思います。

Settingsバンドルは、ビルド前あるいはビルド中に更新しても問題なさそうです。

前述のSettingsバンドルの記事では、Info.plistからCFBundle文字列を取ってきて、それを使ってバンドル内のプロパティリストファイルに更新をかけていますが、いまの.pbxprojの仕組みであれば、単に「${MARKETING_VERSION}」「${CURRENT_PROJECT_VERSION}」を使って更新すれば良いと思います。

kabeyakabeya

前述のSettingsバンドルの記事では、Info.plistからCFBundle文字列を取ってきて、それを使ってバンドル内のプロパティリストファイルに更新をかけていますが、いまの.pbxprojの仕組みであれば、単に「${MARKETING_VERSION}」「${CURRENT_PROJECT_VERSION}」を使って更新すれば良いと思います。

↓の記事にその話も書いてありました。

https://dev.classmethod.jp/articles/xcode-11-app-version/

kabeyakabeya

新しいプロジェクトを作って同じことをしようとしてすぐに分かりませんでした。
ちゃんと書いておけって話ですね。

  1. Productメニュー→Scheme→Edit Scheme...のBuildタグの「Post-actions」で、左下のプラスボタンを押して「New Run Script Action」を選ぶ。
  2. Provide build settings fromは、「なし」からAppのターゲットに変更する。
  3. xcrun agvtool next-versionの前にcd ${PROJECT_DIR}を入れる。↓の感じ。
# Type a script or drag a script file from your workspace to insert its path.
cd ${PROJECT_DIR}
xcrun agvtool next-version

あと、これをやったとき、複数ターゲット(例えばiOSアプリとウィジェット)があってもすべて更新されますね。
(すべてのターゲットで、↓をやってある前提&その複数ターゲットが一度にビルドされる前提で)

それで「Build」のほうは、プロジェクト→TARGETS→「Build Settings」→「Versioning」→「Versioning System」を「Apple Generic」に変更しておくと、


追記。

これ、なんでしょう。ビルド自体はうまく行くんだけども。
ビルドが終わると、Swift Package Managerの依存関係がプロジェクトファイルから消えてしまいます。
(プロジェクトを開き直すと復活している)
Xcode 15.3ですが、バグですかね。


さらに追記。

xcrun agvtool next-versionを呼ばなければ、問題なさそうですね。
どうしたもんかな。


2024/10/6 追記。

Xcode 16.0 (16A242d)では直って(=依存関係が消えなくなって)いました。