🐡

Androidアプリ起動時の初期化処理

2024/12/19に公開

これは株式会社TimeTree Advent Calendar 2024の19日目の記事です。

こんにちは。TimeTreeのAndroidエンジニアの笠松です。

この記事ではTimeTreeのAndroidアプリの初期化周りの処理をご紹介します。特に以下の内容を取り上げます。

  • スプラッシュ画面起動前の初期化処理
  • スプラッシュ画面起動開始時の初期化処理
  • フォアグラウンド時、バックグランド時の処理登録

スプラッシュ画面起動前の初期化処理

TimeTreeでは、Androidの公式ライブラリであるApp Startupライブラリを採用しています。

本ライブラリはアプリ起動時のコンポーネント初期化をサポートします。本ライブラリは単一のコンテンツプロバイダを利用して初期化する仕組みを提供するため、コンテンツプロバイダに依存したコンポーネントの初期化を効率的に行うことができます。

使用方法は以下のコードのようにcreate関数で初期化処理を実装し、dependenciesで初期化の順序を指定します。以下の例ではFirstInitializerの初期化が完了したら、SecondInitializerの初期化が起動します。

class SecondInitializer : Initializer<T> {
    override fun create(context: Context): T {
        //初期化処理
    }

    override fun dependencies(): List<Class<out Initializer<*>>> = listOf(
        FirstInitializer::class.java
    )
}

より詳細なマニフェストの設定等は公式ドキュメントをご参照ください。

例えば、Firebaseを初期化する場合、以下のようにFirebaseAppFirebaseCrashlyticsだけをこの段階で初期化します。クラッシュの早期検知を有効化し、それ以外の初期化処理は後回しにすることで、スプラッシュ画面の起動時間を短縮するためです。依存関係がないため、dependenciesは空リストを指定します。

class FirebaseCoreInitializer : Initializer<Boolean> {
    override fun create(context: Context): Boolean {
        FirebaseApp.initializeApp(context)
        FirebaseCrashlytics.getInstance()
        return true
    }

    override fun dependencies(): List<Class<out Initializer<*>>> = emptyList()
}

スプラッシュ画面起動開始時の初期化処理

スプラッシュ画面起動開始時の初期化処理を行うため、以下のようにInitializercreate関数でアプリケーションコールバックを登録し、onActivityCreatedのタイミングで初期化処理を呼び出します。

例えば、FirebaseAnalyticsなどの初期化はこのタイミングで行います。dependenciesFirebaseCoreInitializerを指定し、FirebaseAppの初期化完了後に処理を開始できるようにします。

class AppComponentsInitializer : Initializer<Boolean> {
    ...
    @Inject
    internal lateinit var delegate: ApplicationLifecycleCallbacks

    override fun create(context: Context): Boolean {
        val application = context.applicationContext as Application
        application.registerActivityLifecycleCallbacks(object : DefaultActivityLifecycleCallbacks {
            override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {
                delegate.onAppFirstScreenLaunch(activity)
            }
        })
    }

    override fun dependencies(): List<Class<out Initializer<*>>> = listOf(
        FirebaseCoreInitializer::class.java,
        ...
    )
}

処理を拡張可能にする仕組みとして、以下のコードのようにApplicationLifecycleObserverインターフェイスを定義しています。このインターフェイスを継承するクラスを作成し、Dagger HiltでSetに追加することで、スプラッシュ画面の初回起動時に実行する処理を簡単に追加できます。

interface ApplicationLifecycleObserver {
    fun onAppFirstScreenLaunch(activity: Activity) {}
}

@Singleton
class ApplicationLifecycleCallbacks @Inject constructor(
    private val observers: Provider<Set<@JvmSuppressWildcards ApplicationLifecycleObserver>>
) {
    fun onAppFirstScreenLaunch(activity: Activity) {
        observers.get().forEach { it.onAppFirstScreenLaunch(activity) }
    }
}

フォアグラウンド・バックグラウンド時の処理登録

フォアグラウンド・バックグラウンド時の処理登録を行うため、以下のようにProcessLifecycleOwnerにオブザーバーを登録します。ProcessLifecycleOwnerを使用するためにdependenciesProcessLifecycleInitializerを指定します。

class AppComponentsInitializer : Initializer<Boolean> {
    ...
    @Inject
    internal lateinit var observer: ProcessLifecycleObservers

    override fun create(context: Context): Boolean {
        ProcessLifecycleOwner.get().lifecycle.addObserver(observer)
        ...
    }

    override fun dependencies(): List<Class<out Initializer<*>>> = listOf(
        ProcessLifecycleInitializer::class.java,
        ...
    )
}

フォアグラウンド・バックグラウンド遷移時の処理も、ProcessLifecycleObserverインターフェイスを利用して追加可能です。このインターフェイスを継承するクラスを作成し、Dagger HiltでSetに作成したクラスを追加することで、各契機で実行する処理を簡単に追加できます。

interface ProcessLifecycleObserver {
    fun onAppToForeground(lifecycleOwner: LifecycleOwner) {}
    fun onAppToBackground(lifecycleOwner: LifecycleOwner) {}
}

@Singleton
class ProcessLifecycleObservers @Inject constructor(
    private val observers: Provider<Set<@JvmSuppressWildcards ProcessLifecycleObserver>>
) : DefaultLifecycleObserver {
    override fun onStart(owner: LifecycleOwner) {
        observers.get().forEach { it.onAppToForeground(owner) }
    }

    override fun onStop(owner: LifecycleOwner) {
        observers.get().forEach { it.onAppToBackground(owner) }
    }
}

まとめ

スプラッシュ画面起動前の初期化処理、スプラッシュ画面起動開始時の初期化処理、フォアグラウンド時、バックグランド時の処理登録の実装方法をご紹介しました。
ご紹介した仕組みは各社でそれぞれあると思いますが、ご参考になれば幸いです。

TimeTree Tech Blog

Discussion