import java.util.Properties /** * Tracked replacement for the app module's build script. * * `tauri android init` regenerates gen/android from scratch, so this file is * the source of truth and scripts/sync-android-sources.sh copies it back into * place afterwards. It differs from Tauri's generated version in two ways: * release signing is read from a keystore.properties written by CI, and the * BLE Java sources synced in from the btleplug/jni-utils crates are kept out of * R8's reach. */ plugins { id("com.android.application") id("org.jetbrains.kotlin.android") id("rust") } val tauriProperties = Properties().apply { val propFile = file("tauri.properties") if (propFile.exists()) { propFile.inputStream().use { load(it) } } } // Release signing. CI writes gen/android/keystore.properties from secrets; when // it is absent (any local build) the release variant simply stays debug-signed // rather than failing the build. val keystoreProperties = Properties().apply { val propFile = rootProject.file("keystore.properties") if (propFile.exists()) { propFile.inputStream().use { load(it) } } } android { compileSdk = 36 namespace = "paris.tourolle.bikecontrol" defaultConfig { manifestPlaceholders["usesCleartextTraffic"] = "false" applicationId = "paris.tourolle.bikecontrol" // 24 is Tauri's floor and also btleplug's: the jni-utils Java support // classes use java.util.function, which arrived in API 24. minSdk = 24 targetSdk = 36 versionCode = tauriProperties.getProperty("tauri.android.versionCode", "1").toInt() versionName = tauriProperties.getProperty("tauri.android.versionName", "1.0") } signingConfigs { create("release") { keystoreProperties.getProperty("storeFile")?.let { storeFile = file(it) storePassword = keystoreProperties.getProperty("storePassword") keyAlias = keystoreProperties.getProperty("keyAlias") keyPassword = keystoreProperties.getProperty("keyPassword") } } } buildTypes { getByName("debug") { manifestPlaceholders["usesCleartextTraffic"] = "true" isDebuggable = true isJniDebuggable = true isMinifyEnabled = false packaging { jniLibs.keepDebugSymbols.add("*/arm64-v8a/*.so") jniLibs.keepDebugSymbols.add("*/armeabi-v7a/*.so") jniLibs.keepDebugSymbols.add("*/x86/*.so") jniLibs.keepDebugSymbols.add("*/x86_64/*.so") } } getByName("release") { if (keystoreProperties.getProperty("storeFile") != null) { signingConfig = signingConfigs.getByName("release") } isMinifyEnabled = true proguardFiles( *fileTree(".") { include("**/*.pro") } .plus(getDefaultProguardFile("proguard-android-optimize.txt")) .toList().toTypedArray() ) } } compileOptions { sourceCompatibility = JavaVersion.VERSION_1_8 targetCompatibility = JavaVersion.VERSION_1_8 } kotlinOptions { jvmTarget = "1.8" } buildFeatures { buildConfig = true } } rust { rootDirRel = "../../../" } dependencies { implementation("androidx.webkit:webkit:1.14.0") implementation("androidx.appcompat:appcompat:1.7.1") // requestPermissions via the Activity Result API (MainActivity.kt). implementation("androidx.activity:activity-ktx:1.10.1") implementation("com.google.android.material:material:1.12.0") // btleplug's Java backend and the jni-utils support classes are NOT maven // dependencies: they are copied into app/src/main/java from the crate // sources by scripts/sync-android-sources.sh, so the Java always matches // the Rust in Cargo.lock. Upstream's suggested route — a // 0.1.1-SNAPSHOT artifact published to mavenLocal by hand — cannot be // reproduced on a CI runner and drifts silently from the crate. } apply(from = "tauri.build.gradle.kts")