fastlane活用してますか? fastlane init
でセットアップした設定のままで満足してませんか?
iOS Advent Calendar 2017 4日目はそんなfastlaneのあまり使われていない便利な機能やTipsを、内部実装を参照しながらご紹介したいと思います。
fastlaneに関する基本的な情報は省いています。
***file
fastlaneにはFastfile
の他に、Appfile
、Deliverfile
、Gymfile
、Matchfile
、Scanfile
、Snapfile
といった ***file
という名前のファイルがあります。
これらのファイルはアクションのオプションの設定を外部ファイル化したもので、$ fastlane アクション名 init
で生成できます。
例えば、Deliverfileではdeliver
アクションのオプションを設定できます。
そして、これらのファイルで設定した値はそれぞれのアクションのオプションで 上書き することができます。
つまり、これらのファイルで設定した値は アクションのデフォルト値 を設定していることと同じになります。
できるだけDRYな設定にするためにそのプロジェクトのデフォルト値を設定しておくのが良いと思います。
さらに実は ***file
も Rubyスクリプトとして実行 されています。 (参考: configuration_file.rb)
このため例えば、FastfileやGymfile、Scanfileで同じschemeを設定したい時などは更に外部ファイルにまとめることもできます。
$scheme = 'Foo'
require './global_config'
scheme $scheme
スクリーンショット
既存のiTunes Connectのスクリーンショットをfastlaneで管理するようにしたい場合は、下記のコマンドで設定を取り込むことができます。
$ fastlane deliver download_screenshots
このコマンドでダウンロードされるスクリーンショットの画像名は以下のように非常に扱いにくい名前になっています。
1_ipadPro_1.ftl_d2b40876dd4600114a62fe4b1d1ee2c5_7ae61c6210ffe64c7bfa51cb40c17958.png
1_iphone58_1.ftl_37f4b8484f232d8bfbde853b848faf81_525ba82cc2fb892163529a172224df4b.png
1_iphone6Plus_1.ftl_60c95154387f3d3fe611e8d9a4e2f7ee_2c59dd30d86e2cc938fe1c675fc1832b.png
1_watch_1.ftl_75517b31b5093f6a6879c4673f1a3c90_a4d298b28726c4a657250fadf800fd64.png
2_ipadPro_2.ftl_7cc6f697861a58f6dceb8fd5aa9f00f1_5be9ecf0343b597a23b2cfe7f9c795b0.png
2_iphone58_2.ftl_528d13d986139e781d5f7310a5f71a3a_48ffbe288dc369fd8c079464c2af0c59.png
2_iphone6Plus_2.ftl_a7b9bf20b28549ac0fb1f06f6b32fd88_17b7bf164c9decc3806795314310ef3b.png
2_watch_2.ftl_2f25837af0fd6f968c500217a9ca0c22_9f0e89930847cff409588e3cdb316829.png
3_ipadPro_3.ftl_e3cfaf3978e49c6f87492f6059451a38_161f6bd5437334fd2fc65fd2faf1f527.png
3_iphone58_3.ftl_7b2943a9db21fed000c8b5c0577c0434_3010e41650dcbb7d9aabb81b09d252ff.png
3_iphone6Plus_3.ftl_3c0893d58dc5ce1c2cf245e1662266be_4d4e4e5b949c786f5380bc6b372cf5ee.png
3_watch_3.ftl_2e484db3397f33a725fde60b896e6a62_d1fdb056a78b2961ca2c310f0ca99109.png
4_ipadPro_4.ftl_a4abdc4ddfdf7998e96b2a5eff0b8c90_e49cd62241ee6f8e88bad1b5dcc6e6c9.png
4_iphone58_4.ftl_d66b7ee5b109bef79504c3e198386f59_1de1201d6232244de72c04817ca2bcf5.png
4_iphone6Plus_4.ftl_c4a75fb5e58ea431c1f5f02d77e2aa4f_ab533e3c5ce237d3d141d10ca1104912.png
4_watch_4.ftl_3381b4960ca680c4d3f144d51d1f7438_fe50746a1adbaba0572fa2c0f0f84c71.png
5_ipadPro_5.ftl_447fe5604548d2bb7f3a5d81f312bf4d_e606d0e1bb6fa0c2bf706dcb10c5d0a4.png
5_iphone58_5.ftl_b6f225a3eb25f4a6a79875ad46747e4d_546df9dcb5b9c62e676cb50d21d674a1.png
5_iphone6Plus_5.ftl_31e005781ebf1a8e81fcbeba0789164d_7ad4de588942a91ec6fb391084e5ac9f.png
この名前、実は自由に変えることができます。
内部では画像サイズからデバイスの種類が判定されています。 (参考: app_screenshot.rb)
そして、肝心のスクリーンショットの配置順ですが、これはファイル名の昇順で配置されます。 (参考: upload_screenshots.rb)
つまり、ソート順を意識した名前さえ付けておけばよいわけです。例えば、このような感じです。
1_12.9inch.png
1_5.5inch.png
1_5.8inch.png
1_watch.png
2_12.9inch.png
2_5.5inch.png
2_5.8inch.png
2_watch.png
3_12.9inch.png
3_5.5inch.png
3_5.8inch.png
3_watch.png
4_12.9inch.png
4_5.5inch.png
4_5.8inch.png
4_watch.png
5_12.9inch.png
5_5.5inch.png
5_5.8inch.png
とてもわかりやすくなりましたね
ついでですが、その他メタデータはこのコマンドで既存のiTCの設定を取り込めます。
$ fastlane deliver download_metadata
アクションを作る
fastlaneには便利なアクションが数多く用意されています。アクションの一覧は ここ で確認できます。
ほとんどの場合は既存のアクションを組み合わせることで機能を実現できますが、欲しいアクションがなく、痒いところに手が届かな〜〜いということもあると思います。
そのような時は、まず外部プラグインがないか ここ で探しましょう。そして、それでも見つからない時は自分で作ることになります。
プロジェクト設定
fastlaneにはBundle IdentifierやTeam IDなどを変更できる機能があります。
このようにプロジェクト設定を変更できる機能は、CI/CDで複数の検証用アプリを作り分ける際に非常に便利です。
ビルド番号の更新
自分でアクションを作る必要がある機能の一つに、ビルド番号の更新があります。
fastlaneにはincrement_build_number
というビルド番号を1つ更新してくれるアクションがあります。
内部的にはagvtool next-version -all
というコマンドを実行しているのですが、残念ながらこれが上手く動作しない場合があります。
ビルド番号を「0」, 「1」, 「2」というような番号で管理している場合は問題ないですが、例えばストアバージョンを 「3.0.0」、 ビルド番号を 「3.0.0.5」 というような形式で管理している場合、increment_build_number
実行後のビルド番号は「3.0.0.6」を期待しますが、実際には「4」になってしまいます
このような場合は、既存のアクションを組み合わせて独自のアクションを作ると良いです。
lane :custom_increment_build_number do
# get_build_numberを利用し、現在のビルド番号を取得、末尾の値を取得
trailing_number = get_build_number.split('.').last.to_i
# get_version_numberを利用し、ストアバージョンを取得、ビルド番号の末尾の値を1つ増やして連結
next_build_number = "#{get_version_number}.#{trailing_number + 1}"
# increment_build_numberのオプションに作成したビルド番号を指定し、更新
increment_build_number(build_number: next_build_number)
end
このように既存のアクションを組み合わせて独自の処理を挟むだけで、簡単に既存のプロジェクトの管理方法に合わせた処理を作ることが出来ます。
App Groupsを無効化する
fastlaneの依存ライブラリにはxcodeprojというgemがあり、fastlaneの内部でも多用されています。自分で作る際にはこのgemを活用することをおすすめします。すでにfastlaneで使用されているので、別途gemを入れる必要はありません。
xcodeprojを使った一例ですが、CapabilitiesのApp GroupsをOFFにする機能を作ってみます。
lane :disable_app_groups do
project = Xcodeproj::Project.open('../Foo.xcodeproj') # Fooというプロジェクトの場合
targets_attributes = project.root_object.attributes['TargetAttributes']
project.targets.each do |target|
target_attributes = targets_attributes[target.uuid]
capabilities = target_attributes['SystemCapabilities']
capabilities&.delete 'com.apple.ApplicationGroups.iOS' # Ruby2.3以上
target.build_configuration_list.build_configurations.each do |build_configuration|
entitlements_path = build_configuration.build_settings['CODE_SIGN_ENTITLEMENTS']
next unless entitlements_path
entitlements_path = "./../#{entitlements_path}"
entitlements = Xcodeproj::Plist.read_from_path(entitlements_path)
if entitlements
entitlements.delete 'com.apple.security.application-groups'
Xcodeproj::Plist.write_to_path(entitlements, entitlements_path)
end
end
end
project.save
end
難しそうなこともxcodeprojを利用すると意外とできたりします。足りない機能はこのようにして補っていきましょう。
また、Fastfileにべた書きしていくとFastfileが肥大化してしまうので、プラグイン化や外部ファイル化していくことをおすすめします。
プラグイン化の方法は 公式のドキュメント が参考になります。
便利なアクションが出来たら、本家にプルリクエストを送ってみるのも良いかもしれません
内部の便利クラスを使う
fastlaneには用意されたアクション以外にもアクションの機能実装に利用されている便利なクラスがあります。
これらのクラスを活用すると、アクションの組み合わせでは実現できない機能も作ることが出来ます。
今回はビルドの処理中を待ち、完了後、申請を出す機能を作ってみます。
Spaceship::Tunes
このモジュールを利用すると iTunes Connect へログインしたり、アプリの情報を取得したり出来ます。
ログインしていなければ、ログインする
def login_itc_if_not_logged_in
Spaceship::Tunes.login unless Spaceship::Tunes.client
end
AppFileでapple_id
を設定し、一度ログインをしていれば、入力無しでログインできます。 (Keychainに保存されるため)
iTunes Connectで設定したアプリの情報を取得する
def find_app bundle_id
login_itc_if_not_logged_in
Spaceship::Tunes::Application.find bundle_id
end
app = find_app 'com.bar.foo.***'
puts app
#=> <Spaceship::Tunes::Application
# apple_id="****",
# name="<アプリ名>",
# vendor_id="****",
# bundle_id="****",
# last_modified=<unixtime>,
# issues_count=0,
# app_icon_preview_url="https://****.png",
# version_sets=[<Spaceship::Tunes::VersionSet
# type="APP",
# application=<Spaceship::Tunes::Application #<Object ...>>,
# platform="ios">]>
アプリに関する様々な情報がとれます。 (参考: application.rb)
申請可能なビルドの中で、最新のビルドを取得する
def latest_build app
app.latest_version.candidate_builds
.sort_by {|b| b.upload_date }
.last
end
app = find_app 'com.bar.foo.***'
build = latest_build app
puts build.build_version
ビルドに関する様々な情報がとれます。 (参考: build.rb)
処理中のビルドが終わるのを待つ
上記の機能を組み合わせてレーンを作ってみます。
desc "Wait for the latest build processing"
lane :wait_for_process do |options|
app = options[:app] || find_app 'com.bar.foo.***'
loop do
build = latest_build app
break unless build
break unless build.processing
sleep 30 # 30秒待つ
end
end
最新のビルドを次に申請するアプリのビルドとして設定する
desc "Set the latest build to the latest app version"
lane :set_latest_build do |options|
app = options[:app] || find_app 'com.bar.foo.***'
build = latest_build app
editing_app = app.edit_version
editing_app.select_build build
editing_app.save!
end
処理中ビルドの処理完了後、アプリを申請する
desc "Submit the latest build"
lane :submit_app do |options|
app = options[:app] || find_app 'com.bar.foo.***'
wait_for_process(app: app)
set_latest_build(app: app)
app.create_submission.complete!
end
deliver
のオプションを駆使してもある程度、処理を分割できますが、このように内部のクラスを活用すると、任意の粒度で処理を実行したり、処理内容をカスタマイズしたり出来ます。
CI/CDにこだわりたい方はぜひお試しを
アクション名が変わる!?
実は fastlane 2.68.0 に大きな変更が入っています。
[fastlane] Rename core actions and make aliases for backwards compatibility (#10939) via Mark Pirri
コアアクションのリネーム & 後方互換性のためのエイリアス作成、とあるようにfastlaneのコア機能となっているアクションの名前が変更になったようです。
古い名前 | 新しい名前 |
---|---|
cert | get_certificates |
deliver | upload_to_app_store |
frameit | frame_screenshots |
gym | build_ios_app, build_app |
match | sync_code_signing |
pem | get_push_certificate |
pilot | upload_to_testflight |
precheck | check_app_store_metadata |
produce | create_app_online |
scan | run_tests |
screengrab | capture_android_screenshots |
sigh | get_provisioning_profile |
snapshot | capture_ios_screenshots, capture_screenshots |
supply | upload_to_play_store |
アクションの意味が名前からわかるようになりましたね。
ちなみにですが、fastlane init
を実行してできる初期状態のFastfileのアクション名も変わっていました。
# 一部省略してます
fastlane_version "2.68.0"
default_platform :ios
platform :ios do
desc "Runs all the tests"
lane :test do
run_tests
end
desc "Submit a new Beta Build to Apple TestFlight"
desc "This will also make sure the profile is up to date"
lane :beta do
# match(type: "appstore") # more information: https://codesigning.guide
build_app # more options available
upload_to_testflight
end
desc "Deploy a new version to the App Store"
lane :release do
# sync_code_signing(type: "appstore")
capture_screenshots
build_app # Build your app - more options available
upload_to_app_store(force: true)
# frame_screenshots
end
end
古い名前もエイリアスが貼ってあるため利用できますが、使えなくなる前に移行したほうが良さそうです。
(まるっと実装が移動しました: gym.rb)
また、「build_ios_app, build_app」のようにプラットフォーム名がついているものとついていないもので2つ名前があるアクションがあります。
こちらは、今後、現在のプラットフォームに合わせて挙動を 自動で切り替えてくれる ようになるようです。
例えば、build_app
と書いておくと、現在のプラットフォームがiOSであれば、build_ios_app
、Androidであれば、build_android_app
を裏で実行してくれるようになるようです。
同じ設定で複数のプラットフォームに対応できるようになる日も近いかもしれません。楽しみです。
最後に
時々ソースコードへのリンクを載せましたが、fastlaneで困ったときはソースを読むことをおすすめします。
非常に読みやすく書かれていますので、GitHubの検索を駆使して、メソッドなどを追っていくと意外とわかると思います。
そして、コードへの理解が深まった際にはぜひ、恩返しにコントリビューションしてみてください
凄まじいスピードでレビューし、マージしてくれますよ
以上で、iOS Advent Calendar 2017 4日目はおしまいです。
明日は @takasek さんです