// :app — MainActivity, Application, Hilt wiring (every :core:model interface bound to :data, D-041 and D-085), // navigation and deep links, push handling and notifications, network security and release signing (SPEC §6.2, M8). import java.util.Properties plugins { id("kvitt.android.application") id("kvitt.android.compose") id("kvitt.android.hilt") alias(libs.plugins.google.services) alias(libs.plugins.roborazzi) } // SPEC §10.6: release signing from android/local.properties (git-ignored); without the keys the release build is unsigned. val localProperties = Properties().apply { val file = rootProject.file("local.properties") if (file.isFile) file.inputStream().use { load(it) } } val releaseStoreFile: String? = localProperties.getProperty("kvitt.release.storeFile") // SPEC §10.5.3: the pinned Caddy root replaces the system anchors for icehack.asuscomm.com only when this is true. val pinnedRoot = providers.gradleProperty("kvitt.tls.pinnedRoot").orElse("false").get().toBoolean() android { namespace = "se.hagstedt.kvitt" defaultConfig { applicationId = "se.hagstedt.kvitt" // SPEC §10.6: the release script passes kvitt.versionCode and kvitt.versionName; debug builds use 1 and "dev". versionCode = providers.gradleProperty("kvitt.versionCode").orElse("1").get().toInt() versionName = providers.gradleProperty("kvitt.versionName").orElse("dev").get() } // BuildConfig carries versionCode, versionName and DEBUG into AppBuildInfo (:data, D-041). buildFeatures { buildConfig = true } signingConfigs { if (releaseStoreFile != null) { create("release") { storeFile = file(releaseStoreFile) storePassword = localProperties.getProperty("kvitt.release.storePassword") keyAlias = localProperties.getProperty("kvitt.release.keyAlias") keyPassword = localProperties.getProperty("kvitt.release.keyPassword") } } } buildTypes { debug { applicationIdSuffix = ".debug" } release { if (releaseStoreFile != null) signingConfig = signingConfigs.getByName("release") // SPEC §10.6: R8 shrinks, optimises and obfuscates the release APK; the libraries' consumer rules plus // proguard-rules.pro. publish-apk.sh keeps build/outputs/mapping/release/mapping.txt next to the APK. isMinifyEnabled = true isShrinkResources = true proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro") } } sourceSets { // The pinned-root network security config (and the committed kvitt_root_ca.crt in src/release/res/raw) only // when kvitt.tls.pinnedRoot=true; otherwise src/main's system-anchors config applies. if (pinnedRoot) getByName("release").res.directories.add("src/releasePinnedRoot/res") } } roborazzi { outputDir.set(file("src/test/screenshots")) } dependencies { implementation(project(":core:model")) implementation(project(":core:design")) implementation(project(":domain")) implementation(project(":data")) implementation(project(":adapter:fcm")) implementation(project(":feature:onboarding")) implementation(project(":feature:home")) implementation(project(":feature:account")) implementation(project(":feature:expense")) implementation(project(":feature:settle")) implementation(project(":feature:analytics")) implementation(project(":feature:settings")) testImplementation(project(":core:fakes")) implementation(libs.androidx.core.ktx) implementation(libs.androidx.activity.compose) implementation(libs.androidx.navigation.compose) implementation(libs.androidx.hilt.lifecycle.viewmodel.compose) implementation(libs.androidx.lifecycle.runtime.compose) implementation(libs.androidx.lifecycle.viewmodel.compose) implementation(libs.androidx.lifecycle.process) implementation(libs.androidx.work.runtime.ktx) implementation(libs.kotlinx.coroutines.core) implementation(libs.kotlinx.datetime) implementation(libs.coil) implementation(libs.coil.compose) debugImplementation(libs.androidx.compose.ui.test.manifest) testImplementation(libs.androidx.compose.ui.test.junit4) testImplementation(libs.kotlinx.coroutines.test) testImplementation(libs.robolectric) testImplementation(libs.roborazzi) testImplementation(libs.roborazzi.compose) testImplementation(libs.roborazzi.junit.rule) }