複数のiOSアプリを一斉にアップデートしていたら、気づきにくい罠を3つ踏んだ。どれも地味だが確認が難しい。
1. Firebase Analytics が静かに動いていない
Firebase Analyticsを入れたはずなのに、コンソールにデータが来ない。そういう状態で何ヶ月も運用していたことに気づいた。
DebugViewで確認してみた
いくつかのアプリでAnalytics Dashboardが0のまま動いていなかった。原因を調べるためにXcodeの起動引数に -FIRAnalyticsDebugEnabled を追加して実機で動かしてみた。
コンソールを見ると、こう出ていた。
[FirebaseCrashlytics] Firebase Analytics SDK not detected.
Crash-free statistics and breadcrumbs will not be reported
これはCrashlyticsが出したメッセージだ。Crashlytics自体は import FirebaseCrashlytics があったので正常に動いていた。ただAnalyticsが見当たらないから、クラッシュレポートにスクリーンビューのブレッドクラムが付かない・クラッシュフリー統計がAnalyticsと連携できない、という状態を教えてくれた形だ。
原因はふたつの欠け
ひとつは import FirebaseAnalytics が書かれていないこと。Swiftのリンカーは参照されていないコードをデッドコードとして除去する。FirebaseApp.configure() を呼んでいても、AnalyticsモジュールをSwiftから参照していなければ、ビルド時に丸ごと取り除かれてしまう。
// これだけでは足りない
import FirebaseCore
FirebaseApp.configure()
// こうする
import FirebaseCore
import FirebaseAnalytics // これが必要
FirebaseApp.configure()
もうひとつは -ObjC リンカーフラグがないこと。Firebase AnalyticsはObjective-Cの +load メソッドを使って自分自身を初期化の仕組みに登録する。このフラグがないとObjective-Cのランタイムフックが正しく読み込まれず、Analyticsが起動しない。
SPMで追加していても同じで、Firebase AnalyticsはSPM経由でも静的バイナリ(static XCFramework)として配布されている。静的リンクの場合、参照されていないコードはリンカーが除去するため、-ObjC で明示的に「Obj-Cのクラスは全部含めろ」と伝える必要がある。
Xcode → Target → Build Settings → Other Linker Flags に -ObjC を追加する。
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",
);
どちらか片方でも欠けていると動かない。FirebaseCoreやCrashlyticsは普通に動くのにAnalyticsだけ無効、という状態になる。
import Firebase でまとめて書いている場合は?
import Firebase という書き方をしているアプリは今回の影響を受けにくい。Firebase傘モジュールをインポートすることでAnalyticsへの参照がリンカーに伝わり、除去されずに済む。
ただし -ObjC フラグについては傘インポートの有無に関わらず必要になるケースがある。安全のために追加しておく方がいい。
DebugViewを使うとイベントが見える
-FIRAnalyticsDebugEnabled を起動引数に追加した状態で動かすと、DebugViewにリアルタイムでイベントが流れてくる。screen_view や ad_impression など、実装していなくても自動で収集されるイベントが確認できる。
修正後にコンソールに出てきたログはこんな感じだ。
[FirebaseAnalytics] Analytics v.12.0.0 started
[FirebaseAnalytics] Debug mode is on
[FirebaseAnalytics] Analytics is ready to receive events
[FirebaseAnalytics] Analytics collection enabled
これが出れば正常。
2. CURRENT_PROJECT_VERSION を Info.plist に書いてはいけない
バージョンを sed で自動更新して xcodebuild archive したのに、アーカイブのビルド番号が古いまま、という現象があった。
# project.pbxproj は更新されている
CURRENT_PROJECT_VERSION = 1.0.2.0;
# でもアーカイブは...
/usr/libexec/PlistBuddy -c "Print :ApplicationProperties:CFBundleVersion" App.xcarchive/Info.plist
→ 1.0.1.0 # 古い
原因は Info.plist に直書きされた固定値。
<!-- ❌ これがあると pbxproj の設定が無視される -->
<key>CFBundleVersion</key>
<string>1.0.1.0</string>
<!-- ✅ 変数参照にする -->
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
Xcode の GENERATE_INFOPLIST_FILE を使っているプロジェクトはこの問題が起きにくいが、古いプロジェクトや手書き Info.plist では要注意。
3. Game Center を有効にしているアプリは signingStyle: automatic が必要
CLI で xcodebuild -exportArchive するとき、Game Center や Push Notifications などの Capability を持つアプリでこのエラーが出ることがある。
error: exportArchive "App.app" requires a provisioning profile with the Game Center feature.
exportOptions.plist に signingStyle を追加すると解決する。
<dict>
<key>method</key>
<string>app-store-connect</string>
<key>teamID</key>
<string>YOUR_TEAM_ID</string>
<key>signingStyle</key> <!-- ← これを追加 -->
<string>automatic</string>
<key>uploadSymbols</key>
<true/>
</dict>
automatic にすることで Xcode が Capability に合った証明書・プロビジョニングプロファイルを自動で選んでくれる。
3つに共通すること
どれもアプリが普通に動いているのに気づけない系の問題。Analytics は0件のまま、バージョンは古いまま、エクスポートはエラーで止まる。定期的に確認する仕組みを持つことが大事だと実感した。