はじめに
私は今回のプロジェクトで初めてMobile開発に携わりました。
Web開発からモバイルアプリ(iOS)開発に関わると、メールでたまに謎のファイル「dSYM」をアップロードしてくれと、Firebaseから連絡が着ます。
(Firebase Crashlyticsで、コンソール上に「dSYM が不足しています」という警告が出ます)
私のようなWeb系エンジニアのに合わせて dSYMの正体 を整理し、Firebase Crashlyticsへの自動・手動アップロード手順 を記載したいと思います。
dSYMとは何か?
一言で言うと、dSYM(debug SYMBOL file)は、バイナリ上の暗号のようなクラッシュログを人間が読める形式に変換するための「対応表(ソースマップ)」 です。
なぜ必要なのか?
iOSアプリはコンパイルされると、JavaScriptでいう難読化(Minify/Uglify)や最適化が行われ、変数名や関数名が変換されます。
そのため、ユーザーの端末でクラッシュが発生した際、Firebase Crashlyticsには以下のようなメモリアドレスしか送信されません。
// dSYMがない状態のログ(どこでクラッシュしたか分からない)
Crash at 0x1042f4000 + 12345
ここに dSYM を適用(シンボル化 / Deobfuscation)することで、見慣れたエラーログに変換されます。
// dSYM適用後のログ(ソースコードと行数が特定できる)
UserProfileViewController.swift line 45 in fetchUserData()
Webに置き換えたイメージ
フロントエンド開発(TypeScriptなど)で、ビルド・圧縮されたJSコードのエラーログから元のTSファイル・行数を特定するために Source Map(.mapファイル) を使うのと全く同じ構造です。
dSYMの注意点:ビルドごとに別物が生成される
dSYMファイルには、ビルド(アーカイブ)を実行するたびに固有の UUID が割り当てられます。
- App Storeに提出したビルド
- TestFlightで配信したビルド
- ローカルで実行したビルド
これらはソースコードが1文字も変わっていなくても別々のdSYMになります。そのため、「該当するビルドのバージョンと完全に一致するdSYM」をFirebaseに渡す必要があります。
dSYMのアップロード手順
dSYMをFirebaseに連携する方法は 「ビルド時の自動アップロード」 と 「手動アップロード」 の2種類があり、一般的には自動アップロードで行うみたいです。
私たちのチームでは、過去に自動化しようとしたのですが、"一旦、手動でOK"としてしまったらしく、現在も手動で対応しています。直近で改善したいですね。
(ただ、この手動対応だったからメールが着て、ちゃんと理解するキッカケになったって意味では感謝)
ビルド時の自動アップロード(Xcodeのビルドフェーズで自動化)
毎回のリリースで手動アップロードを行うのはミスの元です。Xcodeの Build Phases にFirebase提供のスクリプトを組み込んで自動化します。
設定手順
- Xcodeでプロジェクト(.xcworkspace / .xcodeproj)を開く
- ターゲット(Target)を選択し、[Build Phases] タブを開く
- 左上の + ボタン > [New Run Script Phase] をクリック
- スクリプトの実行順序を最後(あるいは必要位置)へドラッグし、以下のスクリプトを記述
# CocoaPodsを使用している場合
"${PODS_ROOT}/FirebaseCrashlytics/run"
# Swift Package Manager (SPM)を使用している場合
"${BUILD_DIR%/Build/*}/SourcePackages/checkouts/firebase-ios-sdk/Crashlytics/run"
Input Files の項目に以下のパスを追加します(ビルド時の生成ファイルを指定)
${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}/Contents/Resources/DWARF/${PRODUCT_NAME}${TARGET_BUILD_DIR}/${INFOPLIST_PATH}
余談ですが、最近 CocoaPods から SPM へ変更しました。
手動アップロード(「Missing dSYM」が出た場合)
「自動送信スクリプトが動かなかった」「App Store Connect(App Store / TestFlight)側で生成されたdSYMが必要になった」という(メールが通知された)場合は手動でアップロードします。
手順1:dSYMファイルを取得してZip化
- Xcodeのメニューから [Window] > [Organizer] を開く
- 該当するアーカイブを右クリック > [Show in Finder]
- 生成された .xcarchive ファイルを右クリック > [パッケージの内容を表示]
- dSYMs フォルダを開き、中にある *.app.dSYM を Zip圧縮
Firebaseコンソール(またはCLI)から送信
- GUIからアップロードする場合
- Firebaseコンソール > Crashlytics > ダッシュボード内の「dSYM」タブ(または警告バー)から、作成したZipファイルをドラッグ&ドロップ
- CUI(ターミナル)からアップロードする場合
- プロジェクトルートから以下のコマンド(upload-symbols スクリプト)を実行
# CocoaPodsの場合の例
./Pods/FirebaseCrashlytics/upload-symbols -gsp ./YourApp/GoogleService-Info.plist -p ios /path/to/your/dSYMs.zip
注意点
App Store Connect(TestFlight等)経由のビルドで「Missing dSYM」になる
App Store Connect側でBitcode処理や再コンパイルが行われると、ローカルのXcode手元にあるdSYMとは異なるUUIDのdSYMがApple側で生成されることがあります。
対応方法:
App Store Connect > 対象アプリの [ビルド詳細] > [ビルドファイル] > 「dSYMをダウンロード」 からダウンロードし、上記「方法B」でFirebaseへアップロード
おわりに
Mobile開発の経験が無いので、そもそもをパッと聞けて改善点が見つけられて良かったです。
簡単にできる事って、チーム内にいると意外と改善されないので、素直に聞いて正解でした。
理解もできたので、対応したいと思います!
参考(感謝)
