Files
mihon/app/build.gradle.kts
T
AntsyLich 306befb214 Restrict raw database access to the data module
app no longer touches the database directly. Backup restore's queries move into a new RestoreRepository in :data, which restores a batch of entries all or nothing, stopping between entries if cancelled, as before. The remaining direct calls (excluded scanlators, clear database, backup creation, store and category restore) go through their repositories, and the database bindings move from AppBindings into :data.
2026-09-27 22:30:51 +06:00

377 lines
12 KiB
Kotlin

import com.android.build.api.variant.ApplicationVariant
import com.android.build.api.variant.BuildConfigField
import com.google.firebase.crashlytics.buildtools.gradle.CrashlyticsExtension
import mihon.gradle.Config
import mihon.gradle.getCurrentTime
import mihon.gradle.getLatestCommitCount
import mihon.gradle.getLatestCommitSha
import mihon.gradle.getLatestCommitTime
import mihon.gradle.tasks.ReplaceShortcutsPlaceholderTask
import java.io.FileInputStream
import java.util.Properties
plugins {
alias(mihonx.plugins.android.application)
alias(mihonx.plugins.compose)
alias(mihonx.plugins.spotless)
alias(libs.plugins.metro)
alias(libs.plugins.aboutLibraries)
alias(libs.plugins.androidx.baselineProfile)
alias(libs.plugins.kotlin.serialization)
}
if (Config.includeTelemetry) {
pluginManager.apply {
apply(libs.plugins.google.services.get().pluginId)
apply(libs.plugins.firebase.crashlytics.get().pluginId)
}
}
val keystorePropertiesFile = layout.settingsDirectory.file("keystore.properties").asFile
android {
namespace = "eu.kanade.tachiyomi"
defaultConfig {
applicationId = "app.mihon"
versionCode = 31
versionName = "0.20.4"
buildConfigField("boolean", "TELEMETRY_INCLUDED", "${Config.includeTelemetry}")
buildConfigField("boolean", "UPDATER_ENABLED", "${Config.enableUpdater}")
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
if (System.getenv("MIHON_GITHUB_RELEASE").toBoolean()) {
signingConfigs {
named("debug") {
storeFile = file(System.getenv("storeFile"))
storePassword = System.getenv("storePassword")
keyAlias = System.getenv("keyAlias")
keyPassword = System.getenv("keyPassword")
}
}
} else if (keystorePropertiesFile.exists()) {
val keystoreProperties = FileInputStream(keystorePropertiesFile).use { Properties().apply { load(it) } }
signingConfigs {
named("debug") {
storeFile = file(keystoreProperties.getProperty("storeFile"))
storePassword = keystoreProperties.getProperty("storePassword")
keyAlias = keystoreProperties.getProperty("keyAlias")
keyPassword = keystoreProperties.getProperty("keyPassword")
}
}
}
buildTypes {
val debug = getByName("debug") {
applicationIdSuffix = ".dev"
isPseudoLocalesEnabled = true
}
val release = getByName("release") {
isMinifyEnabled = true
isShrinkResources = true
signingConfig = debug.signingConfig
isProfileable = true
proguardFiles("proguard-android-optimize.txt", "proguard-rules.pro")
}
val commonMatchingFallbacks = listOf(release.name)
create("foss") {
initWith(release)
applicationIdSuffix = ".foss"
matchingFallbacks.addAll(commonMatchingFallbacks)
}
create("nightly") {
initWith(release)
applicationIdSuffix = ".debug"
matchingFallbacks.addAll(commonMatchingFallbacks)
}
create("benchmark") {
initWith(release)
versionNameSuffix = "-benchmark"
applicationIdSuffix = ".benchmark"
matchingFallbacks.addAll(commonMatchingFallbacks)
}
if (Config.includeTelemetry) {
configureEach {
configure<CrashlyticsExtension> {
mappingFileUploadEnabled = Config.uploadCrashlyticsMapping
}
}
}
}
sourceSets {
getByName("nightly").res.directories.add("src/debug/res")
getByName("benchmark").res.directories.add("src/debug/res")
}
splits {
abi {
isEnable = true
isUniversalApk = true
reset()
include("armeabi-v7a", "arm64-v8a", "x86", "x86_64")
}
}
packaging {
jniLibs {
keepDebugSymbols += listOf(
"libandroidx.graphics.path",
"libarchive-jni",
"libconscrypt_jni",
"libimagedecoder",
"libquickjs",
"libsqlite3x",
)
.map { "**/$it.so" }
}
resources {
excludes += setOf(
"kotlin-tooling-metadata.json",
"LICENSE.txt",
"META-INF/**/*.properties",
"META-INF/**/LICENSE.txt",
"META-INF/*.properties",
"META-INF/*.version",
"META-INF/DEPENDENCIES",
"META-INF/LICENSE",
"META-INF/NOTICE",
"META-INF/README.md",
)
}
}
dependenciesInfo {
includeInApk = Config.includeDependencyInfo
includeInBundle = Config.includeDependencyInfo
}
buildFeatures {
viewBinding = true
buildConfig = true
aidl = true
}
lint {
abortOnError = false
checkReleaseBuilds = false
}
}
kotlin {
compilerOptions {
freeCompilerArgs.addAll(
"-opt-in=androidx.compose.animation.ExperimentalAnimationApi",
"-opt-in=androidx.compose.animation.graphics.ExperimentalAnimationGraphicsApi",
"-opt-in=androidx.compose.foundation.ExperimentalFoundationApi",
"-opt-in=androidx.compose.foundation.layout.ExperimentalLayoutApi",
"-opt-in=androidx.compose.material3.ExperimentalMaterial3Api",
"-opt-in=androidx.compose.material3.ExperimentalMaterial3ExpressiveApi",
"-opt-in=androidx.compose.ui.ExperimentalComposeUiApi",
"-opt-in=coil3.annotation.ExperimentalCoilApi",
"-opt-in=kotlinx.coroutines.ExperimentalCoroutinesApi",
"-opt-in=kotlinx.coroutines.FlowPreview",
"-opt-in=kotlinx.coroutines.InternalCoroutinesApi",
"-opt-in=kotlinx.serialization.ExperimentalSerializationApi",
)
}
}
baselineProfile {
baselineProfileOutputDir = "baselineProfiles"
mergeIntoMain = true
}
dependencies {
baselineProfile(projects.baselineProfile)
implementation(projects.i18n)
implementation(projects.icons.materialSymbols)
implementation(projects.icons.simpleIcons)
implementation(projects.core.archive)
implementation(projects.core.common)
implementation(projects.core.metro)
implementation(projects.coreMetadata)
implementation(projects.sourceApi)
implementation(projects.sourceLocal)
implementation(projects.data)
implementation(projects.domain)
implementation(projects.presentationCore)
implementation(projects.presentationWidget)
implementation(projects.telemetry)
// Compose
implementation(libs.androidx.activity.compose)
implementation(libs.androidx.compose.foundation)
implementation(libs.androidx.compose.material3)
implementation(libs.androidx.compose.animation)
implementation(libs.androidx.compose.animationGraphics)
debugImplementation(libs.androidx.compose.uiTooling)
implementation(libs.androidx.compose.uiToolingPreview)
implementation(libs.androidx.compose.uiUtil)
implementation(libs.androidx.interpolator)
implementation(libs.androidx.paging.runtime)
implementation(libs.androidx.paging.compose)
implementation(libs.kotlin.reflect)
implementation(libs.bundles.kotlinx.coroutines)
implementation(libs.kotlinx.datetime)
// AndroidX libraries
implementation(libs.androidx.annotation)
implementation(libs.androidx.appCompat)
implementation(libs.androidx.biometric)
implementation(libs.androidx.constraintLayout)
implementation(libs.androidx.core)
implementation(libs.androidx.coreSplashScreen)
implementation(libs.androidx.recyclerView)
implementation(libs.androidx.viewPager)
implementation(libs.androidx.profileInstaller)
implementation(libs.bundles.androidx.lifecycle)
// Job scheduling
implementation(libs.androidx.work)
// RxJava
implementation(libs.rxJava)
// Networking
implementation(libs.bundles.okhttp)
implementation(libs.okio)
implementation(libs.conscrypt) // TLS 1.3 support for Android < 10
// Data serialization (JSON, protobuf, xml)
implementation(libs.bundles.serialization)
// HTML parser
implementation(libs.jsoup)
// Disk
implementation(libs.diskLruCache)
implementation(libs.unifile)
// Preferences
implementation(libs.androidx.preference)
// Dependency injection
implementation(libs.injekt)
implementation(libs.metro.runtime)
implementation(libs.metrox.viewmodel)
implementation(libs.metrox.viewmodel.compose)
// Image loading
implementation(libs.bundles.coil)
implementation(libs.subsamplingScaleImageView) {
exclude(module = "image-decoder")
}
implementation(libs.image.decoder)
implementation(libs.webgpuviewer)
// UI libraries
implementation(libs.material)
implementation(libs.flexibleAdapter)
implementation(libs.photoView)
implementation(libs.directionalViewPager) {
exclude(group = "androidx.viewpager", module = "viewpager")
}
implementation(libs.composeRichEditor)
implementation(libs.aboutLibraries.compose)
implementation(libs.bundles.voyager)
implementation(libs.composeMaterialMotion)
implementation(libs.swipe)
implementation(libs.composeWebview)
implementation(libs.composeGrid)
implementation(libs.reorderable)
implementation(libs.bundles.markdown)
implementation(libs.materialKolor)
// Logging
implementation(libs.logcat)
// Shizuku
implementation(libs.bundles.shizuku)
// String similarity
implementation(libs.stringSimilarity)
// Tests
testImplementation(libs.bundles.test)
testRuntimeOnly(libs.junit.platform.launcher)
// For detecting memory leaks; see https://square.github.io/leakcanary/
// debugImplementation(libs.leakCanary.android)
implementation(libs.leakCanary.plumber)
testImplementation(libs.kotlinx.coroutines.test)
}
val latestCommitCount = getLatestCommitCount()
val latestCommitSha = getLatestCommitSha()
val latestCommitTime = getLatestCommitTime()
val currentTime = getCurrentTime()
fun ApplicationVariant.buildConfigField(type: String, name: String, value: Provider<String>) {
buildConfigFields?.put(name, value.map { BuildConfigField(type, it, null) })
}
androidComponents {
onVariants { variant ->
val isUnstableBuild = variant.buildType == "debug" || variant.buildType == "nightly"
val buildTime = if (isUnstableBuild) currentTime else latestCommitTime
variant.buildConfigField("String", "COMMIT_COUNT", latestCommitCount.map { "\"$it\"" })
variant.buildConfigField("String", "COMMIT_SHA", latestCommitSha.map { "\"$it\"" })
variant.buildConfigField("String", "BUILD_TIME", buildTime.map { "\"$it\"" })
if (isUnstableBuild) {
variant.outputs.forEach { output ->
val versionName = output.versionName.get()
output.versionName.set(latestCommitCount.map { "$versionName-$it" })
}
}
}
onVariants { variant ->
val resSource = variant.sources.res ?: return@onVariants
val variantName = variant.name.replaceFirstChar { it.uppercase() }
val replaceShortcutsPlaceholderTask = tasks.register<ReplaceShortcutsPlaceholderTask>(
"replace${variantName}ShortcutPlaceholder",
) {
applicationId.set(variant.applicationId)
shortcutsFile.set(projectDir.resolve("src/main/shortcuts.xml"))
}
resSource.addGeneratedSourceDirectory(replaceShortcutsPlaceholderTask) { it.outputDir }
}
onVariants(selector().withFlavor("default" to "standard")) {
// Only excluding in standard flavor because this breaks
// Layout Inspector's Compose tree
it.packaging.resources.excludes.add("META-INF/*.version")
}
}