plugins { id 'com.android.application' id 'org.jetbrains.kotlin.plugin.serialization' version '2.4.20' id 'org.jetbrains.kotlin.plugin.compose' version '2.4.20' id 'jacoco' } android { namespace 'net.helcel.fidelity' compileSdk = 37 ndkVersion "25.2.9519653" //Match this to KeypassDX crypto NDK version defaultConfig { applicationId 'net.helcel.fidelity' // CI derives both from git (see .github/workflows/build.yml); the fallbacks are for local builds. versionName project.hasProperty('VERSION_NAME') ? project.property('VERSION_NAME') : "1.3c" versionCode project.hasProperty('VERSION_CODE') ? project.property('VERSION_CODE').toInteger() : 1 buildConfigField("String", "APP_NAME", "\"Keepass Fidelity\"") manifestPlaceholders["APP_NAME"] = "Keepass Fidelity" minSdk = 28 targetSdk = 37 testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } signingConfigs { register("release") { try { def keystorePropertiesFile = rootProject.file("app/keystore.properties") def keystoreProperties = new Properties() keystoreProperties.load(new FileInputStream(keystorePropertiesFile)) keyAlias keystoreProperties['keyAlias'] keyPassword keystoreProperties['keyPassword'] storeFile file(keystoreProperties['storeFile']) storePassword keystoreProperties['storePassword'] } catch (FileNotFoundException e) { println("File not found: ${e.message}") } } } buildTypes { debug { debuggable true initWith(buildTypes.release) signingConfig signingConfigs.debug enableUnitTestCoverage true } release { minifyEnabled true shrinkResources true proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } signedRelease { initWith(buildTypes.release) matchingFallbacks = ['release'] signingConfig = signingConfigs.getByName("release") } } compileOptions { coreLibraryDesugaringEnabled true sourceCompatibility JavaVersion.VERSION_21 targetCompatibility JavaVersion.VERSION_21 encoding 'utf-8' } buildFeatures { viewBinding true compose true buildConfig true } dependenciesInfo { // Disables dependency metadata when building APKs. includeInApk = false // Disables dependency metadata when building Android App Bundles. includeInBundle = false } composeOptions { kotlinCompilerExtensionVersion = "2.2.20" } testOptions { unitTests { includeAndroidResources = true all { maxParallelForks = 2 forkEvery = 50 maxHeapSize = "1024m" // Robolectric loads classes through its own sandbox classloader, which leaves them // without a code-source location. Without this JaCoCo skips them entirely and the // report only sees the handful of plain JVM classes. jacoco { includeNoLocationClasses = true excludes = ["jdk.internal.*"] } } } } kotlin { jvmToolchain(21) } lint { disable 'UsingMaterialAndMaterial3Libraries' disable 'PreviewAnnotationInFunctionWithParameters' } } dependencies { implementation 'androidx.compose.ui:ui' implementation 'androidx.compose.material3:material3:1.4.0' implementation 'androidx.compose.material:material:1.12.1' implementation 'androidx.compose.material:material-icons-extended:1.7.8' implementation 'androidx.navigation:navigation-compose:2.10.1' implementation 'androidx.preference:preference-ktx:1.2.1' implementation "androidx.biometric:biometric:1.2.0-alpha05" implementation "androidx.security:security-crypto:1.1.0" implementation "androidx.datastore:datastore-preferences:1.2.1" implementation "androidx.security:security-crypto:1.1.0" coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs_nio:2.1.5' implementation 'androidx.camera:camera-lifecycle:1.6.2' implementation 'androidx.camera:camera-view:1.6.2' runtimeOnly 'androidx.camera:camera-camera2:1.6.2' implementation 'com.google.android.material:material:1.14.0' implementation 'org.jetbrains.kotlinx:kotlinx-serialization-json:1.11.0' implementation 'com.google.zxing:core:3.5.4' implementation project(":database") implementation project(":crypto") implementation platform('androidx.compose:compose-bom:2026.09.00') implementation 'androidx.compose.ui:ui-tooling:1.12.1' implementation 'androidx.compose.ui:ui-tooling-preview' //Submodule //noinspection NewerVersionAvailable implementation 'joda-time:joda-time:2.14.3' implementation 'org.joda:joda-convert:3.0.1' testImplementation 'junit:junit:4.13.2' testImplementation 'io.mockk:mockk:1.14.11' testImplementation 'org.robolectric:robolectric:4.17' testImplementation 'androidx.test:core:1.7.0' testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.11.0' testImplementation 'androidx.compose.ui:ui-test-junit4' androidTestImplementation platform('androidx.compose:compose-bom:2026.09.00') androidTestImplementation 'androidx.test.ext:junit:1.3.0' androidTestImplementation 'androidx.test.espresso:espresso-core:3.7.0' androidTestImplementation 'androidx.compose.ui:ui-test-junit4' androidTestImplementation 'io.mockk:mockk-android:1.14.11' debugImplementation 'androidx.compose.ui:ui-test-manifest' } tasks.register('jacocoTestReport', JacocoReport) { dependsOn 'testDebugUnitTest' reports { xml.required = true html.required = true } def fileFilter = ['**/R.class', '**/R$*.class', '**/BuildConfig.*', '**/Manifest*.*', '**/*Test*.*'] def debugTree = fileTree(dir: "${project.layout.buildDirectory.asFile.get()}/intermediates/built_in_kotlinc/debug/compileDebugKotlin/classes", excludes: fileFilter) def mainSrc = "${project.projectDir}/src/main/java" sourceDirectories.from = files([mainSrc]) classDirectories.from = files([debugTree]) executionData.from = fileTree(dir: project.layout.buildDirectory.asFile.get(), includes: [ 'jacoco/testDebugUnitTest.exec', 'outputs/unit_test_code_coverage/debugUnitTest/testDebugUnitTest.exec' ]) }