aboutsummaryrefslogtreecommitdiffstats
path: root/packages/meshbay-android/app/build.gradle.kts
diff options
context:
space:
mode:
Diffstat (limited to 'packages/meshbay-android/app/build.gradle.kts')
-rw-r--r--packages/meshbay-android/app/build.gradle.kts88
1 files changed, 88 insertions, 0 deletions
diff --git a/packages/meshbay-android/app/build.gradle.kts b/packages/meshbay-android/app/build.gradle.kts
new file mode 100644
index 0000000..3f29ac0
--- /dev/null
+++ b/packages/meshbay-android/app/build.gradle.kts
@@ -0,0 +1,88 @@
+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
+ // A stand-in until the release key exists (Stage D12): the debug
+ // key, so a release build installs over a debug one and back
+ // without losing the account. Not a key to publish anything with.
+ signingConfig = signingConfigs.getByName("debug")
+ }
+ }
+ 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")
+ // Ed25519, X25519, HKDF and Argon2id, identical on the JVM and every
+ // Android version: the platform has no Argon2 and its Ed25519 is recent.
+ implementation("org.bouncycastle:bcprov-jdk18on:1.86")
+ // Casting: discovery through MediaRouter, control through the cast sender
+ // SDK and the default media receiver. Needs the vendor's play services at
+ // run time; where they are absent the page is offered no cast at all.
+ implementation("com.google.android.gms:play-services-cast-framework:22.3.1")
+ implementation("androidx.mediarouter:mediarouter:1.8.1")
+ 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/<hash>/ 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>("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)
+ }
+}