Files
ISODroid/app/build.gradle.kts
2026-03-13 23:46:48 +05:00

194 lines
6.6 KiB
Kotlin

import javax.inject.Inject
import org.gradle.process.ExecOperations
plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.kotlin.android)
alias(libs.plugins.kotlin.compose)
}
// Build isodrive native binary from submodule (only if binaries are missing)
abstract class BuildIsodriveTask @Inject constructor(
private val execOps: ExecOperations
) : DefaultTask() {
@get:InputDirectory
abstract val isodriveDir: DirectoryProperty
@get:OutputDirectory
abstract val outputDir: DirectoryProperty
@TaskAction
fun build() {
val isodrivePath = isodriveDir.get().asFile
val outputPath = outputDir.get().asFile
if (!isodrivePath.resolve("src").exists()) {
throw GradleException("isodrive submodule not initialized. Run: git submodule update --init")
}
val sourceFiles = listOf(
"src/util.cpp",
"src/configfsisomanager.cpp",
"src/androidusbisomanager.cpp",
"src/main.cpp"
)
val srcs = sourceFiles.joinToString(" ") { "$isodrivePath/$it" }
val cflags = "-I$isodrivePath/src/include -static-libstdc++ -Os -s"
val compilers = mapOf(
"arm64-v8a" to "aarch64-linux-android26-clang++",
"armeabi-v7a" to "armv7a-linux-androideabi26-clang++",
"x86_64" to "x86_64-linux-android26-clang++",
"x86" to "i686-linux-android26-clang++"
)
val useNixShell = File("/etc/NIXOS").exists() ||
Runtime.getRuntime().exec(arrayOf("which", "nix-shell")).waitFor() == 0
if (useNixShell) {
println("NixOS detected, using nix-shell for NDK...")
val buildScript = compilers.entries.joinToString("\n") { (arch, compiler) ->
val archDir = outputPath.resolve(arch)
val output = archDir.resolve("isodrive")
if (output.exists()) {
"echo 'isodrive for $arch already exists, skipping'"
} else {
"""
mkdir -p "$archDir"
echo "Building isodrive for $arch..."
"${'$'}TOOLCHAIN/$compiler" $cflags $srcs -o "$output"
""".trimIndent()
}
}
execOps.exec {
environment("NIXPKGS_ALLOW_UNFREE", "1")
commandLine("nix-shell", "-p", "androidenv.androidPkgs.ndk-bundle", "--run", """
SDK_ROOT=${'$'}(find /nix/store -maxdepth 1 -name "*android-sdk-ndk*" -type d 2>/dev/null | head -1)
NDK=${'$'}(ls -d "${'$'}SDK_ROOT/libexec/android-sdk/ndk/"* | head -1)
TOOLCHAIN="${'$'}NDK/toolchains/llvm/prebuilt/linux-x86_64/bin"
echo "Using NDK: ${'$'}NDK"
$buildScript
echo "Done building isodrive"
""".trimIndent())
}
} else {
val ndkDir = listOfNotNull(
System.getenv("ANDROID_NDK_HOME"),
System.getenv("ANDROID_NDK")
).firstOrNull { File(it).exists() }
?: throw GradleException("Android NDK not found. Set ANDROID_NDK_HOME or install NDK via SDK Manager.")
val toolchain = "$ndkDir/toolchains/llvm/prebuilt/linux-x86_64/bin"
if (!File(toolchain).exists()) {
throw GradleException("NDK toolchain not found at: $toolchain")
}
compilers.forEach { (arch, compiler) ->
val archDir = outputPath.resolve(arch)
val output = archDir.resolve("isodrive")
if (output.exists()) {
println("isodrive for $arch already exists, skipping")
return@forEach
}
archDir.mkdirs()
println("Building isodrive for $arch...")
execOps.exec {
commandLine("sh", "-c", "$toolchain/$compiler $cflags $srcs -o $output")
}
}
println("Done building isodrive")
}
}
}
val buildIsodrive by tasks.registering(BuildIsodriveTask::class) {
group = "native"
description = "Build isodrive binary for all Android architectures"
isodriveDir.set(rootProject.file("isodrive"))
outputDir.set(file("src/main/assets/bin"))
val architectures = listOf("arm64-v8a", "armeabi-v7a", "x86_64", "x86")
val outDir = file("src/main/assets/bin")
onlyIf { !architectures.all { arch -> outDir.resolve("$arch/isodrive").exists() } }
}
tasks.matching { it.name.startsWith("merge") && it.name.endsWith("Assets") }.configureEach {
dependsOn(buildIsodrive)
}
android {
namespace = "sh.sar.isodroid"
compileSdk = 36
defaultConfig {
applicationId = "sh.sar.isodroid"
minSdk = 26
targetSdk = 36
versionCode = 7
versionName = "1.7"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
isMinifyEnabled = false
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
kotlinOptions {
jvmTarget = "11"
}
buildFeatures {
compose = true
buildConfig = true
}
}
dependencies {
implementation(libs.androidx.core.ktx)
implementation(libs.androidx.appcompat)
implementation(libs.material)
// Compose
implementation(platform(libs.androidx.compose.bom))
implementation(libs.androidx.compose.ui)
implementation(libs.androidx.compose.ui.graphics)
implementation(libs.androidx.compose.ui.tooling.preview)
implementation(libs.androidx.compose.material3)
implementation(libs.androidx.compose.material.icons.extended)
implementation(libs.androidx.activity.compose)
implementation(libs.androidx.lifecycle.viewmodel.compose)
implementation(libs.androidx.lifecycle.runtime.compose)
implementation(libs.androidx.navigation.compose)
debugImplementation(libs.androidx.compose.ui.tooling)
// libsu for root access
implementation(libs.libsu.core)
implementation(libs.libsu.service)
// DataStore for preferences
implementation(libs.androidx.datastore.preferences)
// Coil for image loading (SVG support)
implementation(libs.coil.compose)
implementation(libs.coil.svg)
testImplementation(libs.junit)
androidTestImplementation(libs.androidx.junit)
androidTestImplementation(libs.androidx.espresso.core)
}