iOS アプリの dSYM を CI 経由で Crashlytics に 継続的に Upload する Tips
(2023年1月21日追記)
Xcode 14 からは Bitcode が廃止されたため、この対応が必要なくなりました。読んでくださった方ありがとうございました。
==
1日に1回、 dSYM をまとめてアップロードするスケジュールを作ることで CI 実行時間の浪費を避ける Tips を紹介します。
dSYM ( Debug SYMBOL )
iOS アプリ開発において、若干運用に苦労するポイントとして、 dSYM ( Debug SYMBOL ) 管理があります。
iOS アプリのクラッシュ情報を収集するために、多くのユーザーが Firebase Crashlytics を利用していると思いますが、 Firebase Crashlytics 上で収集したアプリの難読化されたクラッシュログを読みやすいフォーマットに復元するために dSYM ファイルをアップロードする必要があるからです。
/path/to/pods/directory/FirebaseCrashlytics/upload-symbols -gsp /path/to/GoogleService-Info.plist -p ios /path/to/dSYMs
BitCode を ON にしているアプリだと......
通常は上記のページで書かれているような、 upload-symbols コマンドを実行すればよしなにアップロードできますが、 アプリの BitCode を ON にしているアプリだと、 AppStoreConnect にアップロードされるため、 AppStoreConnect にログインして、 dSYM ファイルをダウンロードしてくる必要があります。
ここで AppStoreConnect の2段階認証を乗り越えるために、SMS を経由してなんとかしようと紆余曲折した時期もあるんですが、現在では AppStoreConnect API ver.1.6 から該当URLが取得できるようになり、 Fastlane を利用して容易に取得することができるようになりました。
でもアプリバイナリを Upload してから dSYM が反映されるまでとにかく遅い!!
実際には CI 上ではこんな手順になると思います。
0. (テストとか)
1. $ xcodebuild archive
2. AppStoreConnect へ Upload
---
AppStoreConnect 上で Upload したアプリバイナリが反映されるのを待つ!!
---
3. $ upload-symbols を実行
この反映時間がアプリのサイズにも寄りますが、だいたい40分ほど待たされます。その間 CI は待機して待たなければいけません。 Fastlane の download_dsyms
action にはこのために wait_for_dsym_processing
wait_timeout
といったオプションパラメータがついていて、待つことができます。
download_dsyms(
app_identifier: "com.shimastripe.App",
wait_for_dsym_processing: true,
build_number: 100,
wait_timeout: 3600
)
しかし、このやり方では CI は契約プランに応じて実行時間で従量課金が発生するため、とても燃費が悪いです。 Deploy するごとに何も作業しない40分強を消費することはなんとか避けたいです。
(あと AppStoreConnect の機嫌次第で遅延やエラーが起きて失敗するときもあります。)
ただ dSYM のアップロードが漏れるとうっかり急増するクラッシュが認知できない可能性もあるため、 AppStoreConnect に上げられたアプリバイナリの dSYM は基本漏れずに Crashlytics に送っておくことは実現したい...!! です。
やり方として2つの方法が考えられます。
- Deploy してから N 分後に新しいアクションをスケジュールする仕組みを構築する
- 1日に1回、上がった dSYM をまとめてアップロードするスケジュールを作る
1のやり方ができたら良かったんですが、これは CI の機能に依存してしまうかつ、遅延スケジュールができる CI って現状ある......? となったため、2の方法を紹介します。
1日に1回、上がった dSYM をまとめてアップロードする
Fastlane の download_dsyms
action には after_uploaded_date
というオプションパラメータがあります。これは 一定時刻から後に上がった dSYM ファイルをまとめてダウンロードできます。
つまり、実行時間から1日前を計算して、指定したものを定期実行してしまえば、1日に1回まとめて dSYM を上げておいてくれる仕組みができるわけです!!
こんなかんじ
binary_path = "${BUILD_DIR%Build/*}\/SourcePackages\/checkouts\/firebase-ios-sdk\/Crashlytics\/upload-symbols"
yesterday = DateTime.now - 1
download_dsyms(
app_identifier: "com.shimastripe.App",
after_uploaded_date: "#{yesterday.iso8601}"
)
upload_symbols_to_crashlytics(
gsp_path: "#{PROJECT_DIR}/App/GoogleService-Info.plist",
binary_path: "#{binary_path}"
)
# Delete downloaded dSYM files
clean_build_artifacts
解決!!
これで最大1日遅延しても、dSYM が適切にアップロードされる状態を1日5分ほどの実行時間で実現できます!! やった!!
これをスケジュールに登録して、CI に後は任せましょう!!
開発要件によりますが、平日だけ実行に留めてもいいかもしれませんね。
==
ちなみに Swift Package Manager 越しに firebase-ios-sdk
を入れて upload-symbols
コマンドを呼ぶ場合上記の書き方で DerivedData
越しにスクリプトを実行することができます。便利ですね。
Discussion