Firebaseを使っているとGoogleService-Info.plist
なるファイルをプロジェクト内に配置するよう指示されますよね。
FirebaseのNotificationやAnalytics、CrashReportなどは開発版とリリースされているものとは混ぜたくないので、環境別に自動的にGoogleService-Info.plist
を切り替えさせたかったのですが、それがなかなかに面倒だったのでメモっておきます。
前提:Configurationsの分類
私が現在作成しているアプリでは1つのプロジェクト内に複数の環境(Configuration)を存在させています。
以下のような感じにConfigurationsを分類し、Bundle IDを環境別に変化させることでそれぞれ別アプリとして認識させています。
Configuration名 | Bundle ID Suffix | 用途 | 運用方針 |
---|---|---|---|
Staging Debug | .Staging.Debug | 普段の開発ビルド用 | ステージングサーバへアクセスしつつデバッグ情報などを表示させる |
Staging Release | .Staging | 社内配布やテスト用 | ステージングサーバへアクセスしつつデバッグ情報などは表示させない |
Production Debug | .Debug | 本番環境でデバッグしたい時に | 本番サーバへアクセスしつつデバッグ情報などを表示させる |
Production Release | なし | 本番リリース用 | 本番サーバへアクセスしつつデバッグ情報などは表示させない |
これに合わせてSchemeもStaging
とProduction
の2つ作成しており、Runした場合はそれぞれの環境のDebug版が実行され、Archiveした場合は必ずRelease版がビルドされるようにしています。
あとはアプリ名、アイコンもそれぞれの環境で変更することで事故が起こらないようにしています。
手順
1. Firebase上のプロジェクトにアプリをConfiguration分作成する
開発版とリリース版など環境ごとにFirebaseの管理を分けたいのでその分だけFirebaseのプロジェクトにアプリを作成します。今回の場合だと最終的に以下のような感じになると思います
細かい手順は公式リファレンスを見ていただくのが早いです。
2. GoogleService-Info.plist
を名前を変えて全部プロジェクトに配置する
次はGoogleService-Info.plist
をダウンロードしてプロジェクトに配置します
細かい手順は公式リファレ(ry
ですがどのplistをダウンロードしても同じ名前で落ちてくるためそれぞれ環境別に区別がつくように名前を変更します
Xcodeに追加すると以下のような感じになっていると思います(名前は一例です)
ちなみにですが、実はXcodeのプロジェクトに追加しておく必要は無いです。
後述のRunScriptで参照できる場所にあればいいのでXcode上で見えていなくても問題ないのですが、私は気分的に追加しつつipaには含まれないようにtargetからは外しています。
3. Run Scriptで無理やり環境別のGoogleService-Info.plist
を適用する
デフォルトではFirebaseライブラリはルート階層にあるGoogleService-Info.plist
という名前のファイルを参照しに行くため、それぞれのビルド環境ごとのplistファイルをコピーします。
PROJECTファイル -> TARGETS -> Build Phases -> + -> New Run Script Phaseをタップして新しいスクリプトを作成して以下のスクリプトを貼り付けて下さい
※パスやらConfiguration名やらが含まれているため、各々の環境に合わせて適宜読み替えて下さい
if [ "${CONFIGURATION}" = "Staging_Debug" ]; then
cp "${PROJECT_DIR}/${PROJECT_NAME}/Configurations/GoogleService-Info-Staging-Debug.plist" "${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.app/GoogleService-Info.plist"
echo "Staging Debug GoogleService-Info copied."
elif [ "${CONFIGURATION}" = "Staging_Release" ]; then
cp "${PROJECT_DIR}/${PROJECT_NAME}/Configurations/GoogleService-Info-Staging-Release.plist" "${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.app/GoogleService-Info.plist"
echo "Staging Release GoogleService-Info copied."
elif [ "${CONFIGURATION}" = "Production_Debug" ]; then
cp "${PROJECT_DIR}/${PROJECT_NAME}/Configurations/GoogleService-Info-Production-Debug.plist" "${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.app/GoogleService-Info.plist"
echo "Production Debug GoogleService-Info copied."
elif [ "${CONFIGURATION}" = "Production_Release" ]; then
cp "${PROJECT_DIR}/${PROJECT_NAME}/Configurations/GoogleService-Info-Production-Release.plist" "${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.app/GoogleService-Info.plist"
echo "Production Release GoogleService-Info copied."
fi
4. Crash Reportのシンボルファイル自動アップロードに対応する
※Crash Reportが不要であればこの手順は不要です。
Crash Reportを使っている場合は公式リファレンスの手順にある通り人間が読める状態にするためシンボルファイルのアップロードスクリプトを追加する必要があります。
(手動でシンボルファイルをアップロードしてもいいですがかったるくてやってらんないですw)
このスクリプト内にはGoogleAppIdを記述するよう指示があるためここも環境別に分岐出来るようスクリプトを修正します。
GoogleAppIdはGoogleService-Info.plist
内に記述されているので各環境のplistから引っ張ってきて下さい。
※パスやらConfiguration名やらが含まれているため、各々の環境に合わせて適宜読み替えて下さい(2度目)
特に最後のjsonファイル名は各々異なるようなので変更はお忘れなく。
# Replace this with the GOOGLE_APP_ID from your GoogleService-Info.plist file
if [ "${CONFIGURATION}" = "Staging_Debug" ]; then
GOOGLE_APP_ID=1:xxxxxxxxxxxx:ios:xxxxxxxxxxxx
echo "Configure Staging Debug"
elif [ "${CONFIGURATION}" = "Staging_Release" ]; then
GOOGLE_APP_ID=1:xxxxxxxxxxxx:ios:xxxxxxxxxxxx
echo "Configure Staging Release"
elif [ "${CONFIGURATION}" = "Production_Debug" ]; then
GOOGLE_APP_ID=1:xxxxxxxxxxxx:ios:xxxxxxxxxxxx
echo "Configure Production Debug"
elif [ "${CONFIGURATION}" = "Production_Release" ]; then
GOOGLE_APP_ID=1:xxxxxxxxxxxx:ios:xxxxxxxxxxxx
echo "Configure Production Release"
fi
# Replace the /Path/To/ServiceAccount.json with the path to the key you just downloaded
"${PODS_ROOT}"/FirebaseCrash/upload-sym "${PROJECT_DIR}/${PROJECT_NAME}/Configurations/bigfive-15e55-firebase-crashreporting-8v6br-f8d6143138.json"
2つのスクリプトを追加するとBuild Phasesにはこんな感じになっているはずです
これで作業は完了です。あとはビルドが通ればおkです
ポエム:FIROptions()じゃダメな理由
ここまでやってといてなんですが、実はFirebaseライブラリには使用するGoogleService-Info.plist
を指定できるオプションがあります。
なので以下のようにコード側で環境別にファイル名を明示することで簡単に切り替えることが出来ます。
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
let firbaseOptions = FIROptions(contentsOfFile: Bundle.main.path(forResource: "GoogleService-Info-Staging-Debug", ofType: "plist"))!
FIRApp.configure(with: firbaseOptions)
return true
}
しかしながら、この方法で問題になるのはCrash Reportのシンボルファイル自動アップロードスクリプトです。
このスクリプトの本体はFirebaseのライブラリに含まれているのですが、このスクリプト内にGoogleService-Info.plist
という名前がハードコーディングされているため別の名前にしているとうまくアップロード出来ません。
こっちのほうが正統派っぽいやり方なので、最初この方法でやろうとしたら出来なくてストレスで寿命がマッハになりかけたので皆様もお気をつけ下さい。
ちなみにAndroidでは?
Androidアプリ開発においてはProductFlaverやBuildTypeによって使用するソースフォルダを分けることができるので、上記のiOSのConfigurationと同じようなFlaverを作り、そのフォルダごとにGoogleService-Info.plist
をそのまま配置すればいいので楽ちんです