SPMでFirebase Crashlyticsを複数のアプリに導入したとき、Run Scriptまわりで同じエラーを何度も踏んだ。エラーメッセージで検索しても古いCocoaPods前提の情報が多かったので、SPM + 最近のXcode(User Script Sandboxing有効)での対処をまとめておく。
前提: Run Scriptを設定しないとdSYMが上がらない
Crashlyticsは import FirebaseCrashlytics と FirebaseApp.configure() だけでもクラッシュ自体は記録される。ただしシンボル化(どのファイルの何行目で落ちたか)には dSYM のアップロードが必要で、これはXcodeのBuild Phasesに Run Script を手動で追加しないと行われない。
コンソールのクラッシュレポートが「Missing dSYM」のまま中身が読めない場合、ほぼこれが原因だ。
Run Script の正しい書き方(SPM版)
CocoaPodsなら "${PODS_ROOT}/FirebaseCrashlytics/run" だが、SPMの場合はビルドディレクトリ内のcheckoutsを参照する。
Target → Build Phases → 「+」→ New Run Script Phase で以下を追加する。
"${BUILD_DIR%Build/*}SourcePackages/checkouts/firebase-ios-sdk/Crashlytics/run" \
-gsp "${SRCROOT}/<AppName>/GoogleService-Info.plist"
<AppName> は GoogleService-Info.plist を置いているディレクトリに置き換える。
さらに Input Files に plist を必ず登録する。
$(SRCROOT)/<AppName>/GoogleService-Info.plist
そして 「For install builds only」にチェックを入れる。dSYMアップロードはアーカイブ時だけ必要で、毎回のデバッグビルドで走らせるとビルドが遅くなるだけだ。
ここから、この設定を省略・間違えたときに出るエラーを順に見ていく。
エラー1: Could not get GOOGLE_APP_ID
error: Could not get GOOGLE_APP_ID in Google Services file from build environment
run スクリプトを引数なしで呼ぶと出る。スクリプトはビルド環境変数から GoogleService-Info.plist を探そうとするが、SPM構成では見つけられないことが多い。
対処は -gsp オプションでplistの場所を明示すること。
"${BUILD_DIR%Build/*}SourcePackages/checkouts/firebase-ios-sdk/Crashlytics/run" \
-gsp "${SRCROOT}/<AppName>/GoogleService-Info.plist"
エラー2: Unable to read Google Service plist
error: Unable to read Google Service plist at path ...
-gsp でパスを正しく指定しているのに読めないと言われるケース。原因はXcodeの User Script Sandboxing(Xcode 14以降のテンプレートではデフォルト有効)だ。
Sandboxingが有効だと、Run ScriptはInput Files / Output Filesに宣言されていないファイルへアクセスできない。パスが正しくても、宣言がなければ読み取りがブロックされる。
対処はRun Scriptの Input Files にplistを追加すること。
$(SRCROOT)/<AppName>/GoogleService-Info.plist
ENABLE_USER_SCRIPT_SANDBOXING = NO にして回避する手もあるが、サンドボックスはビルドの再現性のためにあるので、Input Filesへの登録で解決する方が筋がいい。
無視していい警告: サードパーティSDKのdSYM
アーカイブしてApp Store Connectにアップロードすると、こんな警告が返ってくることがある。
The archive did not include a dSYM for the FirebaseAnalytics.framework ...
The archive did not include a dSYM for the GoogleMobileAds.framework ...
これはFirebaseやGoogle Mobile AdsのSDKがプリコンパイル済みバイナリ(XCFramework)として配布されていることによるもので、自分のビルドでは生成しようがない。自分のアプリ本体のdSYMが上がっていれば、自分のコードのクラッシュはシンボル化される。サードパーティSDK内部のスタックフレームが読めないだけなので、実害はほぼない。
毎回出るので最初は不安になるが、これは仕様だ。
動作確認
設定後、本当にレポートが届くかはテストクラッシュで確認できる。
import FirebaseCrashlytics
// デバッグ用ボタンなどから
fatalError("Crashlytics test crash")
注意点がふたつ。
- Xcodeのデバッガをデタッチして実行すること。デバッガが接続されているとクラッシュレポートが横取りされてCrashlyticsに届かない。一度ビルドした後、Xcodeを止めてホーム画面からアプリを起動する。
- クラッシュレポートは次回起動時に送信される。クラッシュさせた後にもう一度アプリを起動して数分待つと、コンソールに表れる。
まとめ
| 症状 | 原因 | 対処 |
|---|---|---|
| Missing dSYM | Run Script未設定 | SPMパスでRun Scriptを追加 |
| Could not get GOOGLE_APP_ID | plistの場所が伝わっていない | -gsp で明示 |
| Unable to read Google Service plist | User Script Sandboxing | Input Filesにplistを登録 |
| SDKのdSYM警告 | プリコンパイル配布の仕様 | 無視してよい |
どれもエラーメッセージが原因を直接言ってくれないタイプなので、同じところで止まっている人の参考になれば。