import org.jetbrains.kotlin.gradle.tasks.KotlinCompile plugins { id "com.android.application" id "kotlin-android" id "kotlin-parcelize" id "com.google.devtools.ksp" id "org.jetbrains.kotlin.plugin.compose" id "org.jetbrains.kotlin.plugin.serialization" id "com.github.triplet.play" id "org.jlleitschuh.gradle.ktlint" } android { namespace "io.nekohasekai.sfa" compileSdk 36 ndkVersion "28.0.13004108" def ndkPathFromEnv = System.getenv("ANDROID_NDK_HOME") if (ndkPathFromEnv != null) { ndkPath ndkPathFromEnv } ksp { arg("room.incremental", "true") arg("room.schemaLocation", "$projectDir/schemas") } defaultConfig { applicationId "io.nekohasekai.sfa" minSdk 21 targetSdk 35 versionCode getVersionProps("VERSION_CODE").toInteger() versionName getVersionProps("VERSION_NAME") setProperty("archivesBaseName", "SFA-" + versionName) } signingConfigs { release { storeFile file("release.keystore") storePassword getProps("KEYSTORE_PASS") keyAlias getProps("ALIAS_NAME") keyPassword getProps("ALIAS_PASS") } } buildTypes { debug { if (getProps("KEYSTORE_PASS") != "") { signingConfig signingConfigs.release } } release { minifyEnabled true proguardFiles getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro" signingConfig signingConfigs.release vcsInfo.include false } } dependenciesInfo { includeInApk = false } flavorDimensions "vendor" productFlavors { play { minSdk 23 } other { minSdk 23 } otherLegacy { minSdk 21 } } sourceSets { play { java.srcDirs += ['src/minApi23/java'] aidl.srcDirs += ['src/minApi23/aidl'] } other { java.srcDirs += ['src/minApi23/java', 'src/github/java'] aidl.srcDirs += ['src/minApi23/aidl'] } otherLegacy { java.srcDirs += ['src/minApi21/java', 'src/github/java'] } } splits { abi { enable true universalApk true reset() include "armeabi-v7a", "arm64-v8a", "x86", "x86_64" } } compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } buildFeatures { viewBinding true aidl true compose true } applicationVariants.configureEach { variant -> variant.outputs.configureEach { outputFileName = (outputFileName as String).replace("-release", "") outputFileName = (outputFileName as String).replace("-play", "-play") outputFileName = (outputFileName as String).replace("-otherLegacy", "-legacy-android-5") outputFileName = (outputFileName as String).replace("-other", "") } } } dependencies { // libbox playImplementation(files("libs/libbox.aar")) otherImplementation(files("libs/libbox.aar")) otherLegacyImplementation(files("libs/libbox-legacy.aar")) // API level specific versions def lifecycleVersion23 = "2.10.0" def roomVersion23 = "2.8.4" def workVersion23 = "2.11.0" def cameraVersion23 = "1.5.2" def browserVersion23 = "1.9.0" def lifecycleVersion21 = "2.9.4" def roomVersion21 = "2.7.2" def workVersion21 = "2.10.5" def cameraVersion21 = "1.4.2" def browserVersion21 = "1.9.0" // Common dependencies (no API level difference) implementation "androidx.core:core-ktx:1.17.0" implementation "androidx.appcompat:appcompat:1.7.1" implementation "com.google.android.material:material:1.13.0" implementation "androidx.constraintlayout:constraintlayout:2.2.1" implementation "androidx.navigation:navigation-fragment-ktx:2.9.6" implementation "androidx.navigation:navigation-ui-ktx:2.9.6" implementation "com.google.zxing:core:3.5.4" implementation "androidx.coordinatorlayout:coordinatorlayout:1.3.0" implementation "androidx.preference:preference-ktx:1.2.1" implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.10.2" implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.9.0" implementation "com.blacksquircle.ui:editorkit:2.2.0" implementation "com.blacksquircle.ui:language-json:2.2.0" implementation("com.android.tools.smali:smali-dexlib2:3.0.9") { exclude group: "com.google.guava", module: "guava" } implementation "com.google.guava:guava:33.5.0-android" // API 23+ dependencies (play/other) playImplementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycleVersion23" playImplementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycleVersion23" playImplementation "androidx.room:room-runtime:$roomVersion23" playImplementation "androidx.work:work-runtime-ktx:$workVersion23" playImplementation "androidx.camera:camera-view:$cameraVersion23" playImplementation "androidx.camera:camera-lifecycle:$cameraVersion23" playImplementation "androidx.camera:camera-camera2:$cameraVersion23" playImplementation "androidx.browser:browser:$browserVersion23" playAnnotationProcessor "androidx.room:room-compiler:$roomVersion23" kspPlay "androidx.room:room-compiler:$roomVersion23" otherImplementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycleVersion23" otherImplementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycleVersion23" otherImplementation "androidx.room:room-runtime:$roomVersion23" otherImplementation "androidx.work:work-runtime-ktx:$workVersion23" otherImplementation "androidx.camera:camera-view:$cameraVersion23" otherImplementation "androidx.camera:camera-lifecycle:$cameraVersion23" otherImplementation "androidx.camera:camera-camera2:$cameraVersion23" otherImplementation "androidx.browser:browser:$browserVersion23" kspOther "androidx.room:room-compiler:$roomVersion23" // API 21 dependencies (otherLegacy) otherLegacyImplementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycleVersion21" otherLegacyImplementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycleVersion21" otherLegacyImplementation "androidx.room:room-runtime:$roomVersion21" otherLegacyImplementation "androidx.work:work-runtime-ktx:$workVersion21" otherLegacyImplementation "androidx.camera:camera-view:$cameraVersion21" otherLegacyImplementation "androidx.camera:camera-lifecycle:$cameraVersion21" otherLegacyImplementation "androidx.camera:camera-camera2:$cameraVersion21" otherLegacyImplementation "androidx.browser:browser:$browserVersion21" kspOtherLegacy "androidx.room:room-compiler:$roomVersion21" // Play Store specific playImplementation "com.google.android.play:app-update-ktx:2.1.0" playImplementation "com.google.android.gms:play-services-mlkit-barcode-scanning:18.3.1" // Shizuku (play and other flavors, API 23+ only) def shizukuVersion = '12.2.0' playImplementation "dev.rikka.shizuku:api:$shizukuVersion" playImplementation "dev.rikka.shizuku:provider:$shizukuVersion" playImplementation 'org.lsposed.hiddenapibypass:hiddenapibypass:4.3' otherImplementation "dev.rikka.shizuku:api:$shizukuVersion" otherImplementation "dev.rikka.shizuku:provider:$shizukuVersion" otherImplementation 'org.lsposed.hiddenapibypass:hiddenapibypass:4.3' // libsu for ROOT package query (all flavors) def libsuVersion = '6.0.0' playImplementation "com.github.topjohnwu.libsu:core:$libsuVersion" playImplementation "com.github.topjohnwu.libsu:service:$libsuVersion" otherImplementation "com.github.topjohnwu.libsu:core:$libsuVersion" otherImplementation "com.github.topjohnwu.libsu:service:$libsuVersion" otherLegacyImplementation "com.github.topjohnwu.libsu:core:$libsuVersion" otherLegacyImplementation "com.github.topjohnwu.libsu:service:$libsuVersion" // Compose dependencies - API 23+ (play/other) def composeBom23 = platform('androidx.compose:compose-bom:2025.12.01') def activityVersion23 = "1.12.2" def lifecycleComposeVersion23 = "2.10.0" playImplementation composeBom23 playImplementation 'androidx.compose.material3:material3' playImplementation 'androidx.compose.ui:ui' playImplementation 'androidx.compose.ui:ui-tooling-preview' playImplementation 'androidx.compose.material:material-icons-extended' playImplementation "androidx.activity:activity-compose:$activityVersion23" playImplementation "androidx.navigation:navigation-compose:2.9.6" playImplementation "androidx.lifecycle:lifecycle-viewmodel-compose:$lifecycleComposeVersion23" playImplementation 'androidx.compose.runtime:runtime-livedata' otherImplementation composeBom23 otherImplementation 'androidx.compose.material3:material3' otherImplementation 'androidx.compose.ui:ui' otherImplementation 'androidx.compose.ui:ui-tooling-preview' otherImplementation 'androidx.compose.material:material-icons-extended' otherImplementation "androidx.activity:activity-compose:$activityVersion23" otherImplementation "androidx.navigation:navigation-compose:2.9.6" otherImplementation "androidx.lifecycle:lifecycle-viewmodel-compose:$lifecycleComposeVersion23" otherImplementation 'androidx.compose.runtime:runtime-livedata' // Compose dependencies - API 21 (otherLegacy) def composeBom21 = platform('androidx.compose:compose-bom:2025.01.00') def activityVersion21 = "1.11.0" def lifecycleComposeVersion21 = "2.9.4" otherLegacyImplementation composeBom21 otherLegacyImplementation 'androidx.compose.material3:material3' otherLegacyImplementation 'androidx.compose.ui:ui' otherLegacyImplementation 'androidx.compose.ui:ui-tooling-preview' otherLegacyImplementation 'androidx.compose.material:material-icons-extended' otherLegacyImplementation "androidx.activity:activity-compose:$activityVersion21" otherLegacyImplementation "androidx.navigation:navigation-compose:2.9.6" otherLegacyImplementation "androidx.lifecycle:lifecycle-viewmodel-compose:$lifecycleComposeVersion21" otherLegacyImplementation 'androidx.compose.runtime:runtime-livedata' // Debug/Test dependencies debugImplementation 'androidx.compose.ui:ui-tooling' debugImplementation 'androidx.compose.ui:ui-test-manifest' androidTestImplementation 'androidx.compose.ui:ui-test-junit4' // Common Compose-related libraries implementation "sh.calvin.reorderable:reorderable:3.0.0" implementation "com.github.jeziellago:compose-markdown:0.5.4" implementation "org.kodein.emoji:emoji-kt:2.3.0" } def playCredentialsJSON = rootProject.file("service-account-credentials.json") if (playCredentialsJSON.exists()) { play { serviceAccountCredentials = playCredentialsJSON defaultToAppBundles = true def version = getVersionProps("VERSION_NAME") if (version.contains("alpha") || version.contains("beta") || version.contains("rc")) { track = "beta" } else { track = "production" } } } tasks.withType(KotlinCompile.class).configureEach { kotlinOptions { jvmTarget = "1.8" } } def getProps(String propName) { def propsInEnv = System.getenv("LOCAL_PROPERTIES") if (propsInEnv != null) { def props = new Properties() props.load(new ByteArrayInputStream(Base64.decoder.decode(propsInEnv))) String value = props[propName] if (value != null) { return value } } def propsFile = rootProject.file("local.properties") if (propsFile.exists()) { def props = new Properties() props.load(new FileInputStream(propsFile)) String value = props[propName] if (value != null) { return value } } return "" } def getVersionProps(String propName) { def propsFile = rootProject.file("version.properties") if (propsFile.exists()) { def props = new Properties() props.load(new FileInputStream(propsFile)) String value = props[propName] if (value != null) { return value } } return "" } ktlint { android = false version = "1.0.1" verbose = true outputToConsole = true reporters { reporter "plain" reporter "checkstyle" reporter "html" } }