import groovy.json.JsonSlurper plugins { id("com.android.application") } // One version for every package (CLAUDE.md): read from the desktop client's // package.json rather than written a second time here. val packageVersion = (JsonSlurper().parse(rootDir.resolve("../meshbay-client/package.json")) as Map<*, *>)["version"] as String val versionParts = packageVersion.split(".").map { it.toInt() } android { namespace = "org.meshbay.client" compileSdk = 37 defaultConfig { applicationId = "org.meshbay.client" minSdk = 26 targetSdk = 36 versionName = packageVersion versionCode = versionParts[0] * 10000 + versionParts[1] * 100 + versionParts[2] } buildTypes { getByName("release") { isMinifyEnabled = false } } compileOptions { sourceCompatibility = JavaVersion.VERSION_17 targetCompatibility = JavaVersion.VERSION_17 } buildFeatures { buildConfig = true } testOptions { unitTests.isReturnDefaultValues = false } } dependencies { implementation("androidx.webkit:webkit:1.17.1") implementation("com.squareup.okhttp3:okhttp:5.5.0") testImplementation("junit:junit:4.13.2") // Android's org.json is a stub on the JVM; the unit tests need the real one. testImplementation("org.json:json:20260814") } /** * The interface, copied from its single source at build time (§8.3). * * `meshbay-hub/src/meshbay_hub/static/` is the interface for the web, the * desktop application and this one. The copy lands in build/ and is never * committed, so it cannot fork. The page itself is the desktop application's * `scripts/index.html` — the hub builds its own with a /a// prefix that * would point back at the hub — so an application loading from its package * has one page, not two. */ abstract class SyncUi : DefaultTask() { @get:InputDirectory abstract val staticDir: DirectoryProperty @get:InputFile abstract val indexHtml: RegularFileProperty @get:OutputDirectory abstract val outputDir: DirectoryProperty @TaskAction fun copy() { val ui = outputDir.get().asFile.resolve("ui") outputDir.get().asFile.deleteRecursively() staticDir.get().asFile.copyRecursively(ui) indexHtml.get().asFile.copyTo(ui.resolve("index.html"), overwrite = true) } } val syncUi = tasks.register("syncUi") { staticDir.set(rootDir.resolve("../meshbay-hub/src/meshbay_hub/static")) indexHtml.set(rootDir.resolve("../meshbay-client/scripts/index.html")) outputDir.set(layout.buildDirectory.dir("generated/ui-assets")) } androidComponents { onVariants { variant -> variant.sources.assets?.addGeneratedSourceDirectory(syncUi, SyncUi::outputDir) } }