import java.io.File import java.util.Properties plugins { alias(libs.plugins.android.application) alias(libs.plugins.kotlin.compose) alias(libs.plugins.kotlin.serialization) alias(libs.plugins.screenshot) } // The Rust core (rust-core/, over oxy-core) is built for the app's ABIs by // cargo-ndk and its Kotlin bindings generated by uniffi at build time // (oxygenhub-android#1): nothing built is kept in the repository. val rustCore: File = rootProject.file("rust-core") val rustJniLibs = layout.buildDirectory.dir("rustJniLibs") val rustBindings = layout.buildDirectory.dir("generated/uniffi/kotlin") fun androidNdk(): String { System.getenv("ANDROID_NDK_HOME")?.let { return it } val props = Properties() val local = rootProject.file("local.properties") if (local.exists()) local.inputStream().use { input -> props.load(input) } val sdk = props.getProperty("sdk.dir") ?: System.getenv("ANDROID_HOME") ?: error("set sdk.dir in local.properties or ANDROID_HOME") val ndks = File(sdk, "ndk").listFiles()?.filter { f -> f.isDirectory }?.sortedBy { f -> f.name }.orEmpty() return ndks.lastOrNull()?.path ?: error("no NDK under $sdk/ndk: install one with the SDK manager") } val buildRustCore = tasks.register("buildRustCore", Exec::class) { description = "Builds rust-core for arm64-v8a and x86_64 with cargo-ndk." workingDir = rustCore inputs.dir(rustCore.resolve("src")) inputs.files(rustCore.resolve("Cargo.toml"), rustCore.resolve("Cargo.lock")) outputs.dir(rustJniLibs) environment("ANDROID_NDK_HOME", androidNdk()) commandLine("cargo", "ndk", "-t", "arm64-v8a", "-t", "x86_64", "--platform", "31", "-o", rustJniLibs.get().asFile.path, "build", "--release") } val generateRustBindings = tasks.register("generateRustBindings", Exec::class) { description = "Generates rust-core's Kotlin bindings with uniffi." dependsOn(buildRustCore) workingDir = rustCore inputs.dir(rustJniLibs) outputs.dir(rustBindings) commandLine( "cargo", "run", "--release", "--bin", "uniffi-bindgen", "generate", "--library", rustJniLibs.get().file("arm64-v8a/librust_core.so").asFile.path, "--language", "kotlin", "--out-dir", rustBindings.get().asFile.path, ) } tasks.named("preBuild") { dependsOn(generateRustBindings) } android { namespace = "io.oxygenhub.android" compileSdk { version = release(37) } defaultConfig { applicationId = "io.oxygenhub.android" minSdk = 31 targetSdk = 37 versionCode = 1 versionName = "1.0" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" } buildTypes { release { optimization { enable = false } } } compileOptions { sourceCompatibility = JavaVersion.VERSION_11 targetCompatibility = JavaVersion.VERSION_11 } packaging { jniLibs { useLegacyPackaging = true } } buildFeatures { compose = true } // README screenshots, rendered from previews without an emulator: // ./gradlew :app:updateDebugScreenshotTest (src/screenshotTest). experimentalProperties["android.experimental.enableScreenshotTest"] = true sourceSets["main"].jniLibs.directories.add(rustJniLibs.get().asFile.path) sourceSets["main"].kotlin.directories.add(rustBindings.get().asFile.path) } dependencies { implementation(libs.jna) { artifact { type = "aar" } } implementation(platform(libs.androidx.compose.bom)) implementation(libs.androidx.activity.compose) implementation(libs.androidx.compose.material3) implementation(libs.androidx.compose.material3.navigation.suite) implementation(libs.androidx.compose.material3.adaptive) implementation(libs.androidx.compose.material3.adaptive.layout) implementation(libs.androidx.compose.material3.adaptive.navigation) implementation(libs.androidx.compose.material.icons.extended) implementation(libs.androidx.compose.ui) implementation(libs.androidx.compose.ui.graphics) implementation(libs.androidx.compose.ui.tooling.preview) implementation(libs.androidx.core.ktx) implementation(libs.androidx.lifecycle.runtime.ktx) implementation(libs.androidx.lifecycle.runtime.compose) implementation(libs.androidx.lifecycle.viewmodel.compose) implementation(libs.androidx.navigation.compose) implementation(libs.kotlinx.serialization.json) implementation(libs.kotlinx.coroutines.android) implementation(libs.okhttp) testImplementation(libs.junit) testImplementation(libs.kotlinx.coroutines.test) testImplementation(libs.okhttp.mockwebserver) androidTestImplementation(platform(libs.androidx.compose.bom)) androidTestImplementation(libs.androidx.compose.ui.test.junit4) androidTestImplementation(libs.androidx.espresso.core) androidTestImplementation(libs.androidx.junit) screenshotTestImplementation(libs.screenshot.validation.api) screenshotTestImplementation(libs.androidx.compose.ui.tooling) screenshotTestImplementation(libs.kotlinx.coroutines.test) debugImplementation(libs.androidx.compose.ui.test.manifest) debugImplementation(libs.androidx.compose.ui.tooling) }