plugins { id("com.android.application") id("org.jetbrains.kotlin.android") id("org.jetbrains.kotlin.plugin.compose") id("com.google.gms.google-services") id("com.google.firebase.crashlytics") id("com.google.dagger.hilt.android") id("com.google.devtools.ksp") } android { namespace = "app.closer" compileSdk = 35 defaultConfig { applicationId = "closer.app" minSdk = 26 targetSdk = 35 versionCode = 1 versionName = "0.1.0" // RevenueCat API key. Set RC_API_KEY in local.properties (never committed). // Debug builds fall back to a placeholder; release builds abort — see task guard below. buildConfigField( "String", "RC_API_KEY", "\"${properties["RC_API_KEY"]?.toString() ?: System.getenv("RC_API_KEY") ?: "PLACEHOLDER_RC_API_KEY"}\"" ) } buildFeatures { buildConfig = true compose = true } buildTypes { release { isMinifyEnabled = true isShrinkResources = true proguardFiles( getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro" ) } } compileOptions { sourceCompatibility = JavaVersion.VERSION_17 targetCompatibility = JavaVersion.VERSION_17 } kotlinOptions { jvmTarget = "17" } packaging { resources.excludes += "META-INF/versions/9/OSGI-INF/MANIFEST.MF" } testOptions { unitTests { isReturnDefaultValues = true isIncludeAndroidResources = true } } } // Abort any release assemble/bundle task when RC_API_KEY is absent or is the placeholder. // This runs at execution time so debug builds are never affected. tasks.matching { it.name.let { n -> (n.startsWith("assemble") || n.startsWith("bundle")) && n.contains("Release", ignoreCase = true) }}.configureEach { doFirst { val key = (findProperty("RC_API_KEY") as? String)?.takeIf { it.isNotBlank() } ?: System.getenv("RC_API_KEY")?.takeIf { it.isNotBlank() } if (key == null || key == "PLACEHOLDER_RC_API_KEY") { throw GradleException( "RC_API_KEY is not set. Add it to local.properties or export RC_API_KEY before running a release build." ) } } } ksp { arg("room.schemaLocation", "$projectDir/schemas") } dependencies { val composeBom = platform("androidx.compose:compose-bom:2025.01.01") implementation(composeBom) implementation("androidx.core:core-ktx:1.15.0") implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.8.7") implementation("androidx.activity:activity-compose:1.9.3") // Compose implementation("androidx.compose.ui:ui") implementation("androidx.compose.ui:ui-graphics") implementation("androidx.compose.ui:ui-tooling-preview") implementation("androidx.compose.material3:material3") implementation("androidx.compose.material:material-icons-extended") // Navigation implementation("androidx.navigation:navigation-compose:2.8.5") // ViewModel implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.8.7") // Firebase implementation(platform("com.google.firebase:firebase-bom:33.8.0")) implementation("com.google.firebase:firebase-auth-ktx") implementation("com.google.firebase:firebase-firestore-ktx") implementation("com.google.firebase:firebase-messaging-ktx") implementation("com.google.firebase:firebase-config-ktx") implementation("com.google.firebase:firebase-analytics-ktx") implementation("com.google.firebase:firebase-crashlytics-ktx") implementation("com.google.firebase:firebase-appcheck-ktx") implementation("com.google.firebase:firebase-appcheck-playintegrity") debugImplementation("com.google.firebase:firebase-appcheck-debug") // Hilt implementation("com.google.dagger:hilt-android:2.53.1") ksp("com.google.dagger:hilt-android-compiler:2.53.1") implementation("androidx.hilt:hilt-navigation-compose:1.2.0") // Room implementation("androidx.room:room-runtime:2.6.1") implementation("androidx.room:room-ktx:2.6.1") ksp("androidx.room:room-compiler:2.6.1") // DataStore implementation("androidx.datastore:datastore-preferences:1.1.2") // Encrypted storage implementation("androidx.security:security-crypto:1.0.0") // Play Integrity API — runtime device integrity check implementation("com.google.android.play:integrity:1.4.0") // Firebase Functions — callable for server-side integrity token verification implementation("com.google.firebase:firebase-storage-ktx") implementation("com.google.firebase:firebase-functions-ktx") // RevenueCat native Android SDK (group: com.revenuecat.purchases, artifact: purchases) implementation("com.revenuecat.purchases:purchases:8.20.0") // Image loading implementation("io.coil-kt:coil-compose:2.7.0") // AppCompat — required by BiometricPrompt (needs FragmentActivity base) implementation("androidx.appcompat:appcompat:1.7.0") // Biometric auth — recovery phrase reveal + app-level login lock implementation("androidx.biometric:biometric:1.1.0") // Google Sign-In via Credential Manager implementation("androidx.credentials:credentials:1.3.0") implementation("androidx.credentials:credentials-play-services-auth:1.3.0") implementation("com.google.android.libraries.identity.googleid:googleid:1.1.1") // Coroutines implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.9.0") // E2EE: Google Tink (AEAD) + Bouncy Castle (Argon2id KDF) implementation("com.google.crypto.tink:tink-android:1.13.0") implementation("org.bouncycastle:bcprov-jdk18on:1.78.1") // Debug debugImplementation("androidx.compose.ui:ui-tooling") debugImplementation("androidx.compose.ui:ui-test-manifest") // Unit tests — JVM only (no device/emulator required) testImplementation("junit:junit:4.13.2") testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.9.0") testImplementation("io.mockk:mockk:1.13.14") }