package __PACKAGE__ import android.app.Application // >>> cmp:feature firebase import __PACKAGE__.data.remote.FIREBASE_FUNCTIONS_REGION import dev.gitlive.firebase.Firebase import dev.gitlive.firebase.auth.auth import dev.gitlive.firebase.firestore.firestore import dev.gitlive.firebase.functions.functions import dev.gitlive.firebase.storage.storage // <<< cmp:feature firebase // >>> cmp:feature room import __PACKAGE__.data.local.AppDatabase import __PACKAGE__.data.local.appContext import __PACKAGE__.data.local.buildDatabase // <<< cmp:feature room import __PACKAGE__.core.connectivity.NetworkMonitor import __PACKAGE__.di.androidModule // >>> cmp:feature inspector import __PACKAGE__.inspector.startInspector // <<< cmp:feature inspector import __PACKAGE__.di.appModules import org.koin.android.ext.koin.androidContext import org.koin.android.ext.koin.androidLogger import org.koin.core.context.startKoin import org.koin.dsl.module class AppApplication : Application() { override fun onCreate() { super.onCreate() // >>> cmp:feature inspector // Debug builds only: the androidRelease twin is a no-op (see inspector/InspectorInit.kt). // Must run before any Activity so the Compose root registry catches every root. startInspector() // <<< cmp:feature inspector // >>> cmp:feature room appContext = this // <<< cmp:feature room // >>> cmp:feature firebase configureFirebaseEmulators() // <<< cmp:feature firebase startKoin { androidLogger() androidContext(this@AppApplication) modules( module { // >>> cmp:feature room single { buildDatabase() } // <<< cmp:feature room single { NetworkMonitor(androidContext()) } }, androidModule, *appModules.toTypedArray() ) } } // >>> cmp:feature firebase // Debug builds talk to the local Firebase emulators (BuildConfig flags set in build.gradle.kts). private fun configureFirebaseEmulators() { if (!BuildConfig.USE_FIREBASE_EMULATORS) return val host = BuildConfig.FIREBASE_EMULATOR_HOST // NOT SWALLOWED. This was `runCatching { … }` with the Result discarded, // and the failure it hid is the worst one this file can produce: a build // that asked for emulators, did not get them, and carried on against the // real project named by google-services.json. Reading, writing and // authenticating against production from a debug build, silently. // // Worse, it hid PARTIAL failure — auth redirected and firestore not, so // half the app talks to the emulator and half to production, which is the // state hardest to notice and hardest to explain afterwards. // // So it throws. The flag above is a deliberate request for emulators; a // debug build that cannot honour it has no safe way to continue. try { Firebase.auth.useEmulator(host, BuildConfig.FIREBASE_AUTH_PORT) Firebase.firestore.useEmulator(host, BuildConfig.FIREBASE_FIRESTORE_PORT) Firebase.functions(FIREBASE_FUNCTIONS_REGION) .useEmulator(host, BuildConfig.FIREBASE_FUNCTIONS_PORT) Firebase.storage.useEmulator(host, BuildConfig.FIREBASE_STORAGE_PORT) } catch (cause: Throwable) { // `throw IllegalStateException(msg, cause)`, never `error(msg)`: error() // takes no cause, so the underlying stack — the only thing that says // WHICH of the four calls failed and why — is dropped and the crash // reads `Cause: null`. throw IllegalStateException( "Firebase emulator redirect to $host FAILED, and this build asked for emulators " + "(USE_FIREBASE_EMULATORS=true). Refusing to start: continuing would authenticate and " + "write against the real project in google-services.json. Usual cause: a Firebase client " + "was already used before this ran, so useEmulator can no longer take effect.", cause, ) } } // <<< cmp:feature firebase }