import java.io.ByteArrayOutputStream val ignoreGitVersion: String by project val acraVersion = "5.12.0" plugins { id("com.android.application") kotlin("android") kotlin("kapt") id("com.mikepenz.aboutlibraries.plugin") id("org.jetbrains.kotlinx.kover") id("app.cash.sqldelight") version "2.0.2" } fun Project.execWithOutput( cmd: String, ignore: Boolean = false, ): String { val result: String = ByteArrayOutputStream().use { outputStream -> project.exec { commandLine = cmd.split(" ") standardOutput = outputStream isIgnoreExitValue = ignore } outputStream.toString() } return result } fun gitVersion(): String { val maybeTagOfCurrentCommit = execWithOutput("git -C ../ describe --contains HEAD", true) val process = if (maybeTagOfCurrentCommit.isEmpty()) { println("No tag on current commit. Will take the latest one.") execWithOutput("git -C ../ for-each-ref refs/tags --sort=-refname --format='%(refname:short)' --count=1") } else { println("Tag found on current commit") execWithOutput("git -C ../ describe --contains HEAD") } return process .replace("^0", "") .replace("'", "") .substring(1) .replace("\\.", "") .trim() } fun versionCodeFromGit(): Int { if (ignoreGitVersion == "true") { // don't care return 1 } println("version code " + gitVersion()) return gitVersion().toInt() } fun versionNameFromGit(): String { if (ignoreGitVersion == "true") { // don't care return "1" } println("version name " + gitVersion()) return gitVersion() } android { compileOptions { isCoreLibraryDesugaringEnabled = true // Flag to enable support for the new language APIs sourceCompatibility = JavaVersion.VERSION_17 targetCompatibility = JavaVersion.VERSION_17 } // For Kotlin projects kotlinOptions { jvmTarget = "17" } compileSdk = 35 buildFeatures { viewBinding = true } defaultConfig { applicationId = "bou.amine.apps.readerforselfossv2.android" minSdk = 25 targetSdk = 34 // 35 when edge-to-edge is handled versionCode = versionCodeFromGit() versionName = versionNameFromGit() multiDexEnabled = true lint { abortOnError = true } vectorDrawables.useSupportLibrary = true // tests testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunnerArguments["clearPackageData"] = "true" testInstrumentationRunnerArguments["useTestStorageService"] = "true" } packaging { resources { excludes += "/META-INF/{AL2.0,LGPL2.1}" } } buildTypes { getByName("release") { isMinifyEnabled = true isShrinkResources = true proguardFiles(getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro") } getByName("debug") { isTestCoverageEnabled = true enableAndroidTestCoverage = true installation { installOptions("-g", "-r") } } } flavorDimensions.add("build") productFlavors { create("githubConfig") { versionNameSuffix = "-github" dimension = "build" } } namespace = "bou.amine.apps.readerforselfossv2.android" testOptions { animationsDisabled = true execution = "ANDROIDX_TEST_ORCHESTRATOR" unitTests { isIncludeAndroidResources = true } } } dependencies { coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.1.4") implementation(project(":shared")) implementation("androidx.appcompat:appcompat:1.7.0") implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.10.1") implementation("androidx.preference:preference-ktx:1.2.1") implementation(fileTree(mapOf("include" to listOf("*.jar"), "dir" to "libs"))) // Android Support implementation("com.google.android.material:material:1.12.0") implementation("androidx.recyclerview:recyclerview:1.4.0-rc01") implementation("androidx.legacy:legacy-support-v4:1.0.0") implementation("androidx.vectordrawable:vectordrawable:1.2.0") implementation("androidx.cardview:cardview:1.0.0") implementation("androidx.annotation:annotation:1.9.1") implementation("androidx.work:work-runtime-ktx:2.10.0") implementation("androidx.constraintlayout:constraintlayout:2.2.0") implementation("org.jsoup:jsoup:1.18.3") // multidex implementation("androidx.multidex:multidex:2.0.1") // About implementation("com.mikepenz:aboutlibraries-core:11.6.3") implementation("com.mikepenz:aboutlibraries:11.6.3") // Material-ish things implementation("com.ashokvarma.android:bottom-navigation-bar:2.2.0") // glide kapt("com.github.bumptech.glide:compiler:4.16.0") implementation("com.github.bumptech.glide:okhttp3-integration:4.16.0") // Themes implementation("com.leinardi.android:speed-dial:3.3.0") // Pager implementation("me.relex:circleindicator:2.1.6") implementation("androidx.viewpager2:viewpager2:1.1.0") // Dependency Injection implementation("org.kodein.di:kodein-di:7.23.1") implementation("org.kodein.di:kodein-di-framework-android-x:7.23.1") implementation("org.kodein.di:kodein-di-framework-android-x-viewmodel:7.23.1") // Settings implementation("com.russhwolf:multiplatform-settings-no-arg:1.3.0") // Logging implementation("io.github.aakira:napier:2.7.1") // PhotoView implementation("com.github.chrisbanes:PhotoView:2.3.0") implementation("androidx.core:core-ktx:1.15.0") implementation("androidx.lifecycle:lifecycle-extensions:2.2.0") // SQLDELIGHT implementation("app.cash.sqldelight:android-driver:2.0.2") // test testImplementation("junit:junit:4.13.2") testImplementation("io.mockk:mockk:1.13.14") testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.1") implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.6.1") androidTestImplementation("androidx.test:runner:1.7.0-alpha01") androidTestImplementation("androidx.test:rules:1.7.0-alpha01") androidTestImplementation("androidx.test.espresso:espresso-core:3.6.1") implementation("androidx.test.espresso:espresso-idling-resource:3.6.1") androidTestImplementation("androidx.test.ext:junit-ktx:1.2.1") androidTestUtil("androidx.test:orchestrator:1.6.0-alpha02") androidTestUtil("androidx.test.services:test-services:1.6.0-alpha02") testImplementation("org.robolectric:robolectric:4.14.1") testImplementation("androidx.test:core-ktx:1.7.0-alpha01") androidTestImplementation("androidx.test.uiautomator:uiautomator:2.3.0") implementation("ch.acra:acra-http:$acraVersion") implementation("ch.acra:acra-toast:$acraVersion") implementation("com.google.auto.service:auto-service:1.1.1") } tasks.withType { outputs.upToDateWhen { false } useJUnit() testLogging { exceptionFormat = org.gradle.api.tasks.testing.logging.TestExceptionFormat.FULL events = setOf( org.gradle.api.tasks.testing.logging.TestLogEvent.PASSED, org.gradle.api.tasks.testing.logging.TestLogEvent.FAILED, org.gradle.api.tasks.testing.logging.TestLogEvent.STANDARD_ERROR, ) showStandardStreams = true } } aboutLibraries { excludeFields = arrayOf("generated") offlineMode = true fetchRemoteLicense = false fetchRemoteFunding = false includePlatform = false strictMode = com.mikepenz.aboutlibraries.plugin.StrictMode.FAIL duplicationMode = com.mikepenz.aboutlibraries.plugin.DuplicateMode.MERGE duplicationRule = com.mikepenz.aboutlibraries.plugin.DuplicateRule.GROUP } // Screenshot failure handling val reportsDirectory = file("$buildDir/reports/androidTests/connected") val clearScreenshotsTask = tasks.register("clearScreenshots") { println("AMINE : clear") commandLine = listOf("adb", "shell", "rm", "-r", "/sdcard/Pictures/selfoss_tests") } val createScreenshotDirectoryTask = tasks.register("createScreenshotDirectory") { println("AMINE : create directory") group = "reporting" commandLine = listOf("adb", "shell", "mkdir", "-p", "/sdcard/Pictures/selfoss_tests") } val fetchScreenshotsTask = tasks.register("fetchScreenshots") { println("AMINE : fetch") group = "reporting" executable(android.adbExecutable.toString()) commandLine = listOf("adb", "pull", "/sdcard/Pictures/selfoss_tests/.", reportsDirectory.toString()) finalizedBy(clearScreenshotsTask) dependsOn(createScreenshotDirectoryTask) doFirst { reportsDirectory.mkdirs() } } tasks.whenTaskAdded { if (this.name == "connectedGithubConfigDebugAndroidTest") { this.finalizedBy(fetchScreenshotsTask) } /* if (this.name == "mergeGithubConfigDebugResources" || this.name == "packageGithubConfigDebugResources" || this.name == "mapGithubConfigDebugSourceSetPaths" || this.name == "extractDeepLinksGithubConfigDebug" ) { this.dependsOn("prepareLibraryDefinitionsGithubConfigDebug") }*/ }