モバイルアプリ向けGoogle Analyticsが、2019年10月末で終了するため、アナリティクス機能をFirebaseへ移行しています。 移行自体は難しい作業ではないはずですが、イベントがなかなか送信されず、僕は2週間もスタックしてしまいました。 原因は、Cocoapodsの設定の仕方でした。今回は、その原因と対策について、まとめておきたいと思います。

症状

Google AnalyticsからFirebaseのアナリティクスへ移行するため、Cocoapodsを使用してFirebase/Analyticsへの依存を追加しました。しかし、自動計測以外のイベント、すなわち自分で追加したアナリティクスのイベントやユーザープロパティのセットなどの処理が、まったく送信されませんでした。

前提

  • FirebaseはAppDelegate内で、正しくFirebaseApp.configure()されている
  • 環境ごとのGoogleService-Info.plistを用意しているが、それらも正しくconfigureメソッドでセットされている
  • 自動で送信されるイベントは、ちゃんと送信される
  • 手動で送信したいイベントは、なぜか送信されない
    • setScreenName
    • logEvent
    • setUserID
    • setUserProperty
  • viewDidAppearで実行するsetScreenNameは、なぜか送信されるが、それ以降は全く動作しない

このように、自動で送信されるイベント + viewDidAppearsetScreenNameしたイベント以降は、まったく送信されませんでした。

自動計測のイベント以降、音沙汰ないDebugView

原因判明のきっかけとなったログ

以下のようなログが出ていないか、チェックします。

objc[25445]: Class FIRAnalytics is implemented in both [library path in target “A”] and [library path in target “B”]. One of the two will be used. Which one is undefined.

つまり、FirebaseがターゲットAのものか、ターゲットBのものか、明確にされていませんというログでした。 なぜ?Firebaseはひとつなのでは……?

複数のtargetのあるプロジェクト

アプリのアーキテクチャ、依存関係に問題がありました。

プロジェクトは、プレゼンテーションレイヤーとモデルレイヤーを分けるため、マルチモジュールの構成 = 複数のターゲットで構成していました。ここでは、アプリとモデルとします。アプリは、モデルに依存しています。さっき見たログは、どちらのターゲットもFirebaseに依存しているために出力されたログでした。

依存関係にある2つのターゲットからFirebaseに依存している

このとき、アプリ内のソースコードで import Firebase を書くと、どのターゲットのFirebaseか判別することができないというわけです。

解決: Cocoapodsの設定 Podfileを修正

こうなった原因は、Podfileの書き方が、複数のターゲットに対して包括的に依存を解決させるようなものになっていたためでした。 ちょうど、Qiitaの記事(Embedded Framework使いこなし術)にあるコメントにあるような設定になっていました。

こんなイメージ。

abstract_target 'MyApp' do
  platform :ios, '8.0'
  use_frameworks!

  pod 'Firebase/Analytics'

  target 'Application' do
    # Firebaseが必要なターゲット
  end

  target 'Model' do
    # 本来、Firebaseが不要のターゲットなのに依存している
  end
end

そこで、Firebaseが必要なターゲットだけFirebaseに依存するように、書き方を変更しました。

abstract_target 'MyApp' do
  platform :ios, '8.0'
  use_frameworks!

  # pod 'Firebase/Analytics' ← こちらは削除

  target 'Application' do
    # Firebaseが必要なターゲット
    pod 'Firebase/Analytics'  # ここに追加
  end

  target 'Model' do
    # 本来、Firebaseが不要のターゲットなのに依存している
  end
end

こうすることで、モデルからFirebaseへの依存がなくなり、FirebaseのAnalyticsが正しく動作するようになりました。

より良いソリューション

ターゲットの依存関係に即してCocoapodsの依存を書いていくのがより理想的なんだと思います。 こちらの記事(CocoaPodsでFirebaseをmain target以外に入れることができない問題(解決済))が参考になります。

まとめ

Firebase向けGoogle Analyticsへ移行していた際に、2週間もスタックしてしまった現象の原因について書きました。 マルチモジュール構成のプロジェクトで、Cocoapodsを使うときは、重複して依存しないように注意しなけれいけないとわかりました。 そして、2週間、まったく見落としていたログに原因があったことから、多くの学びがありました。

  • 問題となっている機能周辺のログは注意深く見ること
  • それでもスタックしたらログを俯瞰し、問題となっている機能以外のログにも目を通すこと

先入観なくログを見ないといけないなと痛感しました。