[Firebase][iOS] Firebase Crashlytics を導入してみたら環境で分けるのにハマった話

「Firebaseを触ってみるシリーズ」です
2019.12.16

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

CX事業本部の中安です
まいどっ、わてがCX事業本部の中安や!

Firebaseを触ってみるシリーズ」の続きになります。

ここまでは

というお題で書かせていただきまして、前回は

を書きましたが、ちょっとCrashlyticsの導入の際にハマったところがあったので、切り出してお話をしようかなと思います。

またもウダウダと書きますが、何かのお役に立てば幸いですやで。

何にハマったのかというと

いったい何にハマったのかというと、タイトルにも書いたのですが「CrashlyticsにおけるFirebaseの環境分け」です。

アプリを開発用環境、ステージング環境、本番環境と分けていて、それぞれにFirebaseのプロジェクトが分かれています。 Firebaseのプロジェクトが分かれているということは設定ファイルも分かれているということです。

基本的に iOS で FirebaseSDK を使って Firebase の機能を使おうとする際には GoogleService-Info.plist というファイルをプロジェクト上に置きますが、この中にある API Key などの値を環境毎に分けるために、ファイル名の拡張子の前に環境の名前をつけて置いていました。

こんな感じ

そして、そのままでは実行時に怒られてしまうので、AppDelegateでFirebaseの初期化をする際に

import UIKit
import Firebase

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
    
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        FirebaseApp.configure(options: firebaseOptions)
        return true
    }
    
    private var firebaseOptions: FirebaseOptions {
        let scheme = (環境名を取ってくる処理 ※割愛)
        let file = Bundle.main.path(
            forResource: "GoogleService-Info.\(scheme)", 
            ofType: "plist"
        )
        return FirebaseOptions(contentsOfFile: file!)!
    }
}

このようにどの設定ファイルを選択するかを環境毎に分岐させていました。

これで、Firebaseの諸機能を使うには何の問題もなかったのですが、前回のプログの手順でやってみたところ

Could not get GOOGLE_APP_ID in Google Services file from build environment.

というエラーが発生してしまいました。

GOOGLE_APP_IDがファイルから取得できない」だと? plistには間違いなくGOOGLE_APP_IDが存在してるのに…。と、そんな感じで少しだけハマってしまいました。

解決へ

分かってみると、そりゃそうだ

先程書いた AppDelegate での FirebaseSDK の初期化処理はもちろん application(_: didFinishLaunchingWithOptions:) に来たときに初めて読み込むファイルが分岐します。

前ブログでも書いたように ScriptPhase のスクリプトが実行されて Crashlytics の初期化が行われるとのことなので、 設定ファイルの読み込みはそれよりも以前のビルドのタイミングで行われ、その際には規定通りGoogleService-Info.plistファイルを見に行こうとします。

つまり、環境ごとに分けていたファイルが意味のないことになってしまってたのですね。

では、どうしよう

この問題を解決したいが、Crashlyticsを導入するだけのために今のファイル構成を変えたりイジったりするのはイヤだなぁということで ビルド時にCrashlytics初期化が実行される前にGoogleService-Info.plistを作ってしまうという手をとることにしました。

下図のように新しく RunScript を追加して

そのスクリプトには以下のように書きました。

PATH_TO_GOOGLE_PLISTS="${PROJECT_DIR}/hoge/fuga"

case "${CONFIGURATION}" in

   "Develop" )
        cp -r "$PATH_TO_GOOGLE_PLISTS/GoogleService-Info.develop.plist" "${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.app/GoogleService-Info.plist" ;;

   "Staging" )
        cp -r "$PATH_TO_GOOGLE_PLISTS/GoogleService-Info.staging.plist" "${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.app/GoogleService-Info.plist" ;;

   "Product" )
        cp -r "$PATH_TO_GOOGLE_PLISTS/GoogleService-Info.product.plist" "${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.app/GoogleService-Info.plist" ;;

   "Release" )
        cp -r "$PATH_TO_GOOGLE_PLISTS/GoogleService-Info.product.plist" "${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.app/GoogleService-Info.plist" ;;

    *)
        ;;
esac

このスクリプトの最初にある PATH_TO_GOOGLE_PLISTS="${PROJECT_DIR}/hoge/fuga" は、それぞれの設定ファイルが置いてあるディレクトリパスを、プロジェクトルートディレクトリを元に定義しています。 プロジェクトによって異なるとは思うので、適宜書き換えます。

case${CONFIGURATION} には、下図のプロジェクトの Configurations のいずれかが入ってきます。

そして、GoogleService-Info.(環境名).plistファイルをビルドされて出来上がるアプリの中にGoogleService-Info.plistの名前にしてコピーしておくわけです。

ビルド時にCrashlytics初期化前にこのスクリプトが走ることで、Crashlyticsは環境毎のGoogleService-Info.plistを読み込むことになります。

ですので、Crashlytics初期化スクリプトよりも上にこのRunScriptは置いておいたほうが良さそうです。

解決

この一手間を加えることによって、Could not get GOOGLE_APP_ID in Google Services file from build environment.というエラーは消え、環境毎のファイルをいじることもなく、環境毎のFirebaseCrashlyticsにクラッシュログを残すことが出来ました。

最後に

FirebaseCrashlyticsを環境毎に分けたいときに、同じようなエラーになって困った方の助けになれば幸いですやで

参考記事

Use different GoogleService-Info.plist for different build schemes