【Android】Firebaseを自動で初期化せずにコードで初期化する


前提

Android Studio 4.1.2
Kotlin 1.3.72
テスト用プロジェクトを作成し以前の記事で導入済み kwn1125.hatenablog.com
コードでの初期化について仕事で調べる機会があったので記事にしておくことにしました。こちらの記事↓を参考にしました。
Google Developers Japan: Android での Firebase の初期化を使いこなす

目標

Firebaseを自動で初期化せずにコードで初期化する。

実装

自動初期化を無効にする

参考記事通りの設定を行います。

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.example.testapplication">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.TestApplication">
        
        〜〜〜省略〜〜〜

        <!-- 追加 -->
        <provider
            android:name="com.google.firebase.provider.FirebaseInitProvider"
            android:authorities="${applicationId}.firebaseinitprovider"
            tools:node="remove" />
    </application>
</manifest>


本当に無効化できているのか、試しに下記のコードを実行してみます。

FirebaseMessaging.getInstance().token.addOnCompleteListener(OnCompleteListener { task ->
    if (!task.isSuccessful) {
        Log.w(TAG, "Fetching FCM registration token failed", task.exception)
        return@OnCompleteListener
    }

    val token = task.result
    Log.d(TAG, "Refreshed token: $token")
})


例外が発生しましたので、ちゃんと無効化できているようです。

java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.testapplication/com.example.testapplication.MainActivity}: java.lang.IllegalStateException: Default FirebaseApp is not initialized in this process com.example.testapplication. Make sure to call FirebaseApp.initializeApp(Context) first.


コードで初期化

FirebaseApp.initializeAppで初期化します。"xxx"に実際の値を入れて試しました。

val builder = FirebaseOptions.Builder()
        .setProjectId("xxx")
        .setApplicationId("xxx")
        .setApiKey("xxx")
FirebaseApp.initializeApp(this, builder.build())


この時最低限何をセットしなければいけないかは使うサービスによって変わってきそうです。とりあえずCloud Messagingの場合は上記のコードで正常に動きました。確認した動作は下記の通りです。

・FCM登録トークンの取得
・Notification Composerから送信した通知の受信

FirebaseAppの名前

FirebaseAppには名前を付けられるのですが、初期化時に名前を指定しないと[DEFAULT]という名前になります。自動で初期化した時も[DEFAULT]です。

// 名前を指定せず初期化
FirebaseApp.initializeApp(this, builder.build())

// 名前を指定して初期化
FirebaseApp.initializeApp(this, builder.build(), "Name")


初期化済みのFirebaseAppをもう一度初期化すると例外が発生する

初期化済みのFirebaseAppをもう一度初期化すると例外が発生します。「名前」と書いてあるところにFirebaseAppの名前が入ります。

java.lang.IllegalStateException: FirebaseApp name 名前 already exists!


なので、初期化済みのFirebaseAppがない場合のみ初期化するようにしたり、

if (FirebaseApp.getApps(this).isEmpty()) {
    FirebaseApp.initializeApp(this, builder.build())
}


特定の名前のFirebaseAppがない場合のみ、初期化するようにすると安全な気がします。

// [DEFAULT]がない場合のみ初期化
if (FirebaseApp.getApps(this).none { it.name.contains("[DEFAULT]") }) {
    FirebaseApp.initializeApp(this, builder.build())
}