Gunosy Tech Blog

Gunosy Tech Blogは株式会社Gunosyのエンジニアが知見を共有する技術ブログです。

iOSアプリのビルド番号自動設定をfastlaneまたはBitriseでラクラク実現する方法

こんにちは。このブログでは初登場の吉岡(@rikusouda) です。GunosyではLUCRAのiOSアプリ開発をメインにやっています。try! Swift Tokyo 2019の開催が近づいてきて、そろそろ楽しみで夜も眠れなくなってきますね。

今回LUCRAのiOSアプリのビルド番号を自動で設定するように運用を変えました。しかし要件を満たす実現方法になかなかたどり着くことができず色々と調べて回りました。やり方さえわかれば本来はそんな苦労をしなくとも fastlane や Bitrise を使うことでシュッと実現できるのでそのあたりをまとめました。

iOSアプリのビルド番号とは

ユーザーに実際に見せるバージョン番号とは別の内部用の管理番号です。 いわゆる Info.plist ファイルに CFBundleVersion として設定される値で、XcodeのTarget設定のGeneralから設定することができます。

例えば、App Store ConnectのTestFlightの画面では下記のように表示されます。

f:id:rikusouda:20190306093153p:plain:w500

下記の説明はAppleの公式見解ではなく私の個人的見解ですが、iOSアプリのビルド番号は下記のような目的や特性を持っていると考えます。

ビルド番号の目的

  • 同じバージョン番号のアプリを区別する(主に社内向け配信)
    • App Store ConnectやTestFlight上ではビルド番号が表示される
    • DeployGateなどでもビルド番号が表示される
  • 特定のバイナリがどのリビジョンでビルドされたかを特定する(デバッグしやすさ)
    • バグが起こったときの発生リビジョン絞り込み

ビルド番号の自動設定をしなくても、ビルド番号を手動で書き換えてから配信することで目的を達成できますが、運用が面倒だと思います。そのためビルド番号の自動設定をしたくなります。

ビルド番号の特性

  • App Store Connectにアップロードするときには数字とピリオドのみで構成しなければならない
    • ピリオドを付けなくてもApp Storeからのリリースができる(2019/3/7現在)
      • 例: 1234
    • 同じバージョンを複数アップロードするためには、前回のビルド番号よりも大きな数値を設定する必要がある
    • 数値とピリオド以外が混ざるとバイナリチェックではねられ、リリースできない
  • App Store Connectにアップロードしない場合はある程度任意の文字列を設定できる
    • 例えばコミットハッシュなど

配信時にApp Store Connectを通すか通さないかで、ビルド番号として設定できる値が異なるところがポイントです。

f:id:rikusouda:20190307160952p:plain:w350

LUCRAでの運用

概要

LUCRA iOSアプリのビルドプロセスは fastlane を使って構成しており Bitrise 上で実行しています。

fastlaneを使って下記のような値を自動設定しています。

配信先 ビルド番号として設定するもの
社内配信(DeployGate) Gitのコミットハッシュ。
d5e3e0c6 のような短い形式
App Store、TestFlight Gitにコミットした回数

配信先によって設定する値を変えている理由ですが、当初は両方ともコミットハッシュでよいと考えました。しかし、App Store Connectがコミットハッシュのようなビルド番号を受け付けないため、ストア用は別にしました。

fastlaneによる設定方法(Bitriseは使っていなくても良い)

Xcode での project.pbxprojの設定

まずは project.pbxproj の CURRENT_PROJECT_VERSION を設定します。これが未設定の場合、実行時にエラーとなってしまいます。設定する値は 1 など何でも良いです。私はこれをしておらず、fastlane実行時にエラーとなり解決に時間がかかりましたのでご注意ください。

f:id:rikusouda:20190305210239p:plain

これが必要な理由は、ビルド番号設定に使うfastlaneのActionが内部で agvtool というコマンドを使っており、このコマンドが CURRENT_PROJECT_VERSION の設定を要求しているためです。

App Storeに配信する場合の Fastfile への記述

  desc "App Store Connectへのアップロード"
  lane :store do
    cocoapods
    carthage

    #★ビルド回数をビルド番号にする
    increment_build_number(
      build_number: number_of_commits
    ) 

    gym
    deliver
  end

上記の store レーンがApp Store Connectへのアップロードをするレーンです。フローを見やすくするため、ビルド番号に関わる記述以外は引数を省略して記載しています。

gym によるビルドをする直前に increment_build_number(build_number: number_of_commits) を実行しているのがポイントです。

increment_build_numberは基本的にはビルド番号をインクリメントするアクションなのですが実は build_number を指定することで任意の値を設定することができます。

number_of_commitsはコミット回数を取得するアクションです。

これらを組み合わせて実行すると Info.plistCFBundleVersion がコミット回数に書き換えられます。

社内配信する場合の Fastfile への記述

  desc "社内向けの配信"
  lane :inhouse do |options|
    cocoapods
    carthage

    #★コミットハッシュをビルド番号にする
    set_build_number_repository 

    gym
    deploygate
  end

上記の inhouse レーンが社内への配信をするレーンです。フローを見やすくするため、ビルド番号に関わる記述以外は引数を省略して記載しています。

gym によるビルドをする直前に set_build_number_repository を実行しているのがポイントです。

set_build_number_repository は fastlane の標準アクションで、Gitのコミットハッシュなどをビルド番号に設定するアクションです。

これを実行すると Info.plistCFBundleVersion がコミットハッシュに書き換えられます。

Info.plist書き換わったままなのが嫌?

LUCRAではBitrise上でこれらを実行しているので、書き換えられた Info.plist は基本的に捨てられるため問題となっていません。もし Info.plist が書き換わったままなのが嫌な場合は backup_filerestore_file で元に戻すことは可能です。

この方法を使うことにした理由

今回ビルド番号の自動設定に求めたのは下記の要件でした。

  • 社内配信版でテストをするのでバグ発生時のリビジョン特定を簡単にしたい
  • App Store Connectに特定バージョンを複数回アップロードしたときに手動でビルド番号を更新するのは避けたい
  • ビルド番号を更新するためにコミットするような運用をしたくない
  • 複雑なシェルスクリプトはあまり管理したくない

要件に合うものを設定したときに見つかったのが下記の2つの方法でした。

  • fastlaneのActionで設定する
  • BitriseのStepで設定する

LUCRAでは今のところfastlaneでビルドプロセスを実現するようにしている事やコミットハッシュの設定が簡単にできそうだったので、BitriseのStepは使わずfastlaneのActionで実現しました。

自前のシェルスクリプトなどを使った方法もいくつか見つかりましたが、自分でスクリプトを管理するよりはfastlaneやBirtiseのStepのようなオープンソースなスクリプトを使い回すほうがメンテナンス性が良いと考えました。

ビルド番号自動設定によってどのように幸せになったか

LUCRAアプリでは社内配信版には専用のデバッグ画面があるのですが、そこでビルド番号が見られるようになっています。

これまでのLUCRAでは、社内配信では基本的にビルド番号を変更しておらず、同じバージョンで同じビルド番号のアプリが複数存在する状況でした。そのため社内配信版でバグが発生したときに、どの配信版からバグが発生するようになったのかの特定がしにくい状況でした。今回のビルド番号自動設定により、必ず異なるビルド番号(コミットハッシュ)が設定されるようになったため下記のような効果がありました。

  • DeployGate上でもビルド番号が見えるので、今どのアプリを使っているのかすぐに分かる
    • テスト、ドッグフードでバグを発見したときに発生バージョンを探しやすい
  • Gitのコミットハッシュと簡単に照合できる
    • バグの原因となったコミットを特定しやすい

とても細かい改善ですが、社内配信アプリを一意に識別できることで作業手順や心理的障壁を減らすことができました。

f:id:rikusouda:20190307161214p:plain:w350

[おまけ] Bitriseを使った実現方法

LUCRAでは採用しませんでしたがBitriseを使った方法も紹介します。fastlaneを使わないプロジェクトでの有力な選択肢だと思います。

Bitriseでは $BITRISE_BUILD_NUMBER という変数があり、Workflowを実行するたびにインクリメントされます。

f:id:rikusouda:20190305195615p:plain:w500

そして Bitriseには Set Xcode Project Build Number というStepがあります。これを使うと $BITRISE_BUILD_NUMBERInfo.plistCFBundleVersion に設定できます。

f:id:rikusouda:20190305200908p:plain

Stepを追加したあとは Info.plist file path に Info.plist へのパスを設定するだけです。

fastlaneを使わずにBitriseでビルドプロセスを構築している場合はこの方法が手軽で良いと思います。

参考: Build numbering and app versioning - Bitrise DevCenter

おわりに

ビルド番号の自動設定まわりは整備しなくてもすぐに困ることが無いためこのあたりを整備する優先度は低めかもしれません。しかし、もし開発対象のプロジェクトがfastlaneやBirtiseのどちらかを利用している、または利用予定であれば今回紹介した仕組みはほとんど手間がかからずに導入できます。

ちなみに、fastlaneのActionもBitriseのStepもソースコードが公開されているので、もし何をしているのかがわからなくて使うのに不安がある場合でも、ソースコードを見るとある程度不安を取り除けると思います。

2019/03/08追記

@_monoさんよりTwitterでコメントをいただきました。

これについてはそのとおりで、コミットハッシュをビルド番号に使うことで、「ひと目でGitのコミットが特定できる」メリットを得る代わりに、ビルド回数を使った場合と比べて「ひと目で順番性がわかる」というメリットを得られなくなります。これについてはDeployGateの配信履歴を参照して順番を特定することで多少カバーすることはできます。

一方、この記事で紹介したBitriseでビルド番号を付ける方法を利用すると、ひと目Gitのコミットを特定することはできませんがBitriseのビルド履歴を参照することでビルド番号からコミットハッシュを特定することができます。

トレードオフを見ながら自分の組織で運用しやすい方法を見つけていくのが良いかもしれません。