📦 FirebaseのSwift Package Manager対応
Xcode 11よりSwift Package Manager (以下、SwiftPM)でライブラリなどの依存をXcodeのGUI上で管理できるようになりました。
かねてよりbetaとしてSwiftPM対応していたFirebaseもv8.0.0よりついに正式に対応されました
SwiftPMはApple純正ツールであり、Xcodeとシームレスにライブラリ管理を実現できる点はCocoaPodsやCarthageと一線を画します。
ビルドのための下準備が不要で、プロジェクトのビルドを実行すれば依存パッケージもそのフローの中で追加されます。
そのため、特に新規のライトなiOSプロジェクトなんかでは第一の選択肢に上がってくるのではないでしょうか。
そんな、SwiftPMを用いてFirebase iOS SDKを導入する手順を示したいと思います!
🔨 導入手順
もちろん、GoogleのFirebase Documentationにもしっかりとドキュメントが存在しています。
Install Firebase with Swift Package Manager | Firebase Documentation
基本的にはそれを読めばOKなのですが、色々と端折られていたり、実際のユースケースにおいてつまづく箇所なども少なくありません。
そういったよくあるシチュエーションの手順も含めた情報として機能すればと思い、筆を走らせています。
🖥 今回のシチュエーションとゴールについて
今回は、よくあるDebug
/ Release
の2つのBuild Configurationを持ったプロジェクトに対し、Firebaseのサービス群の中でもほとんどのアプリで入れることになるであろう、Google Analytics
とCrashlytics
を導入することをゴールとしたいと思います。
それでは、さっそくいってみましょう!
1. SwiftPMでのPackage追加
実は、SwiftPMでのPackage追加方法には下記の2つの方法があります。
- Xcode上からGUIで導入する
-
Package.swift
に記述して導入する
今回は、Xcode上からGUIで導入する手順で説明します。
Package.swift
を用いたこの手順については、公式のFirebase Documentationに記載されているのでそちらを参考にして導入後、次の手順からお読みください
まずは、Firebaseを導入したいプロジェクトファイルをXcodeで開き、メニューバーよりAdd Packagesを選択します。
すると、下記のようなウィンドウが現れるので、右上のサーチバーにフォーカスを合わせ、下記のGitのURLをペーストします。
https://github.com/firebase/firebase-ios-sdk.git
すると、firebase-ios-sdkが表示されるので、Dependency RuleとAdd to Projectに任意のものを選択して右下のAdd Packageを選択します。
なお、Dependency RuleはCocoaPodsやCarthageと同じようなメジャーバージョンが上がらない最新を入れるための記述 Up to Next Major Version
や直接BranchやCommitを指定することができるなど柔軟なルールが選択可能です。
今回は、デフォルトのUp to Next Major Versionかつminimumに8.0.0を指定した状態とします。
詳しい内容が気になる方はこちらをご覧ください。
Adding Package Dependencies to Your App | Apple Developer Documentation
Add Packageを選択後、インジケーターが表示されパッケージのフェッチが行われるので、しばらく待ちます。
フェッチが完了すると、Package Productを選択する画面が表示されます。
今回は、FirebaseAnalyticsWithoutAdIdSupport
とFirebaseCrashlytics
にチェックし、Add Packageを選択します。
FirebaseAnalyticsWithoutAdIdSupport
は、IDFAが不要(iOS 14.5のApp Tracking Transparencyの対応が不要)なFirebaseAnalyticsのパッケージです。
詳しくは下記のDocumentationをご覧ください。
Get started with Google Analytics | Firebase Documentation
すると、Project Navigatorの下部にPackage Dependenciesという欄が表示され、諸々の依存がプロジェクトにインストールされます。
これで、この手順は完了となります。
ここまで一行もコードを書いてないですね
2. Firebaseプロジェクトを開発用/本番用の2つ作成する
Google AnalyticsやCrashlyticsといった解析系サービスは、開発用と本番用で分けておくことに越したことはありません。
開発中のAppの各種イベントやクラッシュがプロダクトの方に紛れてしまっては、解析や集計に支障が出る恐れがあるからです。
そこで、今回は開発用および本番用の2つのFirebaseプロジェクトを作成していきます。
2.1 開発(Debug)用のBundle Identifierを作成する
Firebaseプロジェクトを作る前に、やっておくことがあります。
それは、Debug用のBundle IdentifierをRelease用と分けることです。
これによって、異なるFirebaseプロジェクトを設定することが可能になります。
下記の画像にならって、DebugコンフィグのBundleIDを書き換えます。
一応手順をテキストでも起こしておきます。
- Project Navigatorからプロジェクトを選択
- TARGETS下のAppを選択
- Build Settingsタブを選択
- 検索バーから
bundle identifier
と入力し、Return - Packaging配下のProduct Bundle IdentifierのPulldownを選択
- Configurationごとの設定が可能になるので、DebugのBundleIDのsuffixに
.debug
をつける(任意の名前でOKです)
Appの中にExtensionなど複数のTargetが存在する場合は、同じ手順をTarget分、繰り返します。
この際、watchOSに対応しているアプリなどは
Watck Kit Companion Bundle Identifier
といったInfo.plist
に直接BundleIDを記述している場合がありえます。その場合、DebugコンフィグのBundleIDを分けると突合できずにBuildに失敗してしまうので、User Defined Settings
に変数を作成して定義し、Info.plistのValueにはそれを指定し、定義した変数の値はConfigurationごとに設定するといった手順が必要になる場合があるので、覚えておくと良いでしょう。
2.2 Firebaseプロジェクトの作成 / Google Analyticsの追加
この手順は開発用と本番用で2回同じ動作を行います。それぞれ読み替えて手順を行ってください。
Firebaseコンソールを開き、プロジェクトを追加を選択します。
開発用は<プロジェクト名>-dev
、本番用は<プロジェクト名>
といった名前で作成し続行を選択しましょう。(もちろん名前は任意です)
続いて、Google Analyticsを有効にするか聞かれるので今回は導入するためチェックのまま続行します。
Google Analyticsのアカウントをpulldownより選択します。アカウントがなければ新しいアカウントを作成を選択して新規作成します。
選択できたらプロジェクトを作成を選択するとプロジェクトの作成が完了します。
この画面が表示されたら続行を押すとプロジェクトのコンソール画面が開きます。
コンソール画面が開いたらサイドバーよりDashboardを選択しAnalyticsの画面に遷移します。
そして、iOSを選択してアプリを追加します。
iOSアプリへのFirebaseの追加の画面に遷移するので、それぞれの項目で必要な手順を以下の表に示します。
Firebase上に表示されてる手順に従わず、必ず下記表の手順を実施するようにしてください。
続いて、手順2ではファイルをダウンロードしたら、開発用はGoogleService-Info-Debug.plist
に、本番用はGoogleService-Info-Release.plist
にリネームしておきます。
プロジェクトへの追加はまだやらなくて良いです。
手順3、4、5は何もせず次の手順へ進んでOKです。
一応、上記の手順を表にまとめましたので、参考にしてください。
No. | 手順 |
---|---|
1 アプリの登録 | Firebase上の手順通り |
2 設定ファイルのダウンロード |
GoogleService-Info.plist をダウンロードし次へファイルは開発用は GoogleService-Info-Debug.plist に本番用は GoogleService-Info-Release.plist にリネームしておく(後の手順でプロジェクトにファイルを配置するのでここではしない) |
3 Firebase SDK の追加 | 何もせず次へ |
4 初期化コードの追加 | 何もせず次へ |
5 次のステップ | コンソールに進むを選択 |
これでFirebaseプロジェクトの作成及びAnalyticsの追加は完了です。
2.3 Crashlyticsの追加
こちらの手順も開発用/本番用のそれぞれのプロジェクトで実施してください。
サイドバーからCrashlyticsを選択し、Crashlyticsの画面に遷移したらCrashlyticsを有効にするを選択します。
手順はこれだけです。(実際にクラッシュを飛ばす手順は後で示すので何もしなくて良いです)
これで、Firebase側の設定は全て完了となります。
3. アプリ上でFirebaseを起動する
最後に実際にプロジェクトをビルドしてFirebaseによる解析を開始する手順を示します。
3.1 GoogleService-Info.plistの配置
Analyticsの追加の際のFirebase上の手順には、下記のようにGoogleService-Info.plistファイルをXcodeプロジェクトのルートに移動してくださいという説明がありましたが、この手順を本手順では実施しませんでした。
その理由は、開発用と本番用の2つのplistファイルを同居させたいからでした。
まずは、2.2の手順で実施しておいたリネーム済みの開発用 (GoogleService-Info-Debug.plist
) と本番用 (GoogleService-Info-Release.plist
) の2つのplistファイルをプロジェクトに追加します。
この際、Xcodeプロジェクトのメインターゲットのルートディレクトリから Firebase
というディレクトリを切って、その中にドラッグアンドドロップします。
なお、このディレクトリの名前や構成は任意のもので構いません。
続いて、配置したファイルがビルド時にターゲットのルートに配置されるようなScriptを配置します。
Build Phases上でRun Script Phaseを追加することによって、環境ごとのビルド時に該当のplistファイルがルートに配置されます。
以下のようにして、Run Script Phaseをプロジェクトに追加します。
Scriptはこんな感じです。
(ディレクトリ構成を任意のものにした場合はパスを読み替えて記述してください)
if [ "${CONFIGURATION}" == "Release" ]; then
cp "${PROJECT_DIR}/${PROJECT_NAME}/Firebase/GoogleService-Info-Release.plist" "${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.app/GoogleService-Info.plist"
else
cp "${PROJECT_DIR}/${PROJECT_NAME}/Firebase/GoogleService-Info-Debug.plist" "${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.app/GoogleService-Info.plist"
fi
このScriptを貼り付け、下記のようになっていればOKです。(Run Scriptの名前は任意です)
なお、本手順は下記の記事を参考にさせていただきました
開発版とリリース版でFirebaseのGoogleService-Info.plistを切り替える - Qiita
3.2 Google Analytics用の設定の追加
さて、再掲ですが、こちらのドキュメントには注釈 (Product Specific Considerations
) が書いてあります。
Install Firebase with Swift Package Manager | Firebase Documentation
案内の通り、-ObjC
linker flagを追加していきます。
Google Analytics requires adding the -ObjC linker flag to your target's build settings.
下記のようにして、 Other Linker Flags
に -ObjC
flag を追加してあげればOKです。
3.3 Crashlytics用の設定の追加
つづいて、Crashlytics用の設定を追加していきます。
Product Specific Considerations
には下記のような記載があります。
Crashlytics requires you to upload debug symbols.
You can use a run script for Xcode to automatically upload debug symbols post-build. Find the run script here:
${BUILD_DIR%Build/*}/SourcePackages/checkouts/firebase-ios-sdk/Crashlytics/run
3.1の手順と同じやり方でRun Script Phaseを追加します。
下記のようなScriptが設定できていればOKです。
また、Crashの解析にはdSYMファイルが必要となりますが、DebugビルドはデフォルトではdSYMを生成する設定となっていません。
下記の手順でDebugビルドでもdSYMを生成するように debug information format
を DWARF with dSYM File
に変更しましょう。
3.4 アプリ起動時にFirebaseを起動させる
こちらの手順も先ほど実施しなかった手順となります。
AppDelegate
の起動時に最初に通るDelegateメソッドの didFinishLaunchingWithOptions
に下記のコードを加えます。
import Firebase // Firebase関連の処理を呼びさせるようにimport
...
final class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
// Firebaseの起動
FirebaseApp.configure()
return true
}
}
SwiftUI Appを利用しているプロジェクトでは、AppDelegateがない場合もあるかと思います。
App.swift
の中に下記のような設定を加えることで、AppDelegateにライフサイクル処理を委譲できるオプションがあるので、それを利用するのが良いでしょう。
import SwiftUI
import Firebase
@main
struct SampleApp: App {
@UIApplicationDelegateAdaptor(AppDelegate.self) private var appDelegate
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
final class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
// Firebaseの起動
FirebaseApp.configure()
return true
}
}
これで全ての準備が完了です!お疲れ様でした。
4. 動作検証
お待たせしました。いよいよ動作検証に入っていきます。
4.1 Google Analyticsの動作確認
アプリを起動するだけでAnalytics上にイベントが自動的に飛ぶようになっています。
まずはプロジェクトをDebugコンフィグでBuildしてRunしましょう。
しばらくしたら、Firebaseコンソール上からDashboardを開いて確認すると、データの反映を確認できると思います。
(反映されない場合は、アプリをバックグラウンドにしてからフォアグラウンドに復帰させるなどの手順をお試しください)
念の為、Releaseコンフィグでも同様にちゃんとデータが反映されるか確認するのが安全です。
first_open
のイベントが飛んでいるのが確認できます
4.2 Crashlyticsの動作確認
Crashlyticsの確認には、Crashを発生させないことには話になりません。
そこで簡単なCrashの発生方法を示しておきます。
UIKit Appの場合
UIKitは公式に書いてあるやり方でやるのがいいでしょう。
Get started with Firebase Crashlytics | Firebase Documentation
import UIKit
final class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let button = UIButton(type: .roundedRect)
button.frame = CGRect(x: 20, y: 50, width: 100, height: 30)
button.setTitle("Test Crash", for: [])
button.addTarget(self, action: #selector(self.crashButtonTapped(_:)), for: .touchUpInside)
view.addSubview(button)
}
@IBAction func crashButtonTapped(_ sender: AnyObject) {
let numbers = [0]
let _ = numbers[1]
}
}
SwiftUI Appの場合
SwiftUIのケースも載せておきます。
import SwiftUI
struct ContentView: View {
var body: some View {
Button(
action: {
let numbers = [0]
let _ = numbers[1]
},
label: {
Text("Test Crash")
}
)
}
}
上記の実装を行ったら、実際にBuildしてRunし、一度Debugは中止します。
その後、Debugせずに普通にアプリを起動させ、このCrashを意図的に発生させるようにボタンをタップします。
そしてさらに、もう一度アプリを起動ししばらく待ちます。
Crashをさせた後、再度アプリを起動してしばらく経過させるのがコツとなります。このタイミングでCrashの情報がFirebase上に送信されます。もし送信されてなさそうであればアプリをバックグラウンドにしてからフォアグラウンドに復帰させるなどの手順をお試しください。
下記のようにCrashlyticsの画面に該当のクラッシュ情報が送信されたのが確認できました!
Crashlyticsも同様にReleaseビルドでも動作検証をしておくことをオススメします。
おわりに
いかがだったでしょうか。
だいぶ詳細に説明したのでかなり長くなってしまいましたが、公式にはない実際のユースケースに沿った手順も含めて示すことができたので、ハマりやすい罠もだいぶ踏み抜けたような気がします。
この資料がどなたかの役に立てば幸いです!お読みいただきありがとうございました