diff --git a/android/README.md b/android/README.md index ff2c8b3..8f418ea 100644 --- a/android/README.md +++ b/android/README.md @@ -93,3 +93,30 @@ JUnit Platform (`tasks.test { useJUnitPlatform() }`). > Testing target: **≥80% Kover coverage** on the pure modules (`:wire-protocol`, > `:session-core`, `:api-client`, `:client-tls` pure half). TDD, immutable data, > small focused files — same discipline as the rest of the repo. + +## Android SDK setup (proven working) + +The pure JVM modules need only a JDK + Gradle. The **Android-framework** modules +(`:app`, `:terminal-view`, `:host-registry`, `:client-tls-android` — plan AW2+) +need the Android SDK. This machine is set up and the toolchain is **proven** (an +AGP library module compiled against SDK 35 and produced an AAR): + +- **SDK location:** `/usr/local/share/android-commandlinetools` + (installed via `brew install --cask android-commandlinetools`). +- **Installed packages:** `platform-tools`, `platforms;android-35`, `build-tools;35.0.0`. +- **`android/local.properties`** (gitignored) points Gradle at it: + `sdk.dir=/usr/local/share/android-commandlinetools`. +- **Shell env** (for `sdkmanager`/`adb`): `export ANDROID_HOME=/usr/local/share/android-commandlinetools`. + +### Wiring an Android module (the working recipe) + +- Repos: `google()` is in both `pluginManagement` and `dependencyResolutionManagement` + in `settings.gradle.kts` (needed to resolve AGP + androidx). +- Plugin: **AGP 9.2.1** (`libs.plugins.android.library` / `.android.application`), + compatible with Gradle 9.6.1. +- **Gotcha:** AGP 9 has **built-in Kotlin** — apply ONLY the android plugin. Adding + `org.jetbrains.kotlin.android` errors with "no longer required since AGP 9.0". +- Module block: `android { namespace = "…"; compileSdk = 35; defaultConfig { minSdk = 29 } }`. + +To add more SDK pieces later (e.g. an emulator image for instrumented tests): +`sdkmanager "system-images;android-35;google_apis;arm64-v8a" "emulator"`. diff --git a/android/build.gradle.kts b/android/build.gradle.kts index 21db267..6d7a09b 100644 --- a/android/build.gradle.kts +++ b/android/build.gradle.kts @@ -5,4 +5,8 @@ plugins { alias(libs.plugins.kotlin.jvm) apply false alias(libs.plugins.kotlin.serialization) apply false + // AGP 9.2.1 — proven to build against Android SDK 35 with Gradle 9.6.1. + // AGP 9 has built-in Kotlin; framework modules apply only these (no kotlin.android). + alias(libs.plugins.android.library) apply false + alias(libs.plugins.android.application) apply false } diff --git a/android/gradle/libs.versions.toml b/android/gradle/libs.versions.toml index ea5dfe1..72a74cd 100644 --- a/android/gradle/libs.versions.toml +++ b/android/gradle/libs.versions.toml @@ -4,6 +4,7 @@ ## compatibility with the Kotlin Gradle Plugin on Gradle 9.6). [versions] +agp = "9.2.1" kotlin = "2.3.21" kotlinxSerialization = "1.9.0" kotlinxCoroutines = "1.10.2" @@ -35,3 +36,7 @@ unit-test = ["junit-jupiter", "kotlinx-coroutines-test", "turbine", "mockk"] [plugins] kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" } kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" } +android-library = { id = "com.android.library", version.ref = "agp" } +android-application = { id = "com.android.application", version.ref = "agp" } +# NOTE: AGP 9+ has BUILT-IN Kotlin support — Android modules apply only the +# android plugin, NOT a separate org.jetbrains.kotlin.android (it errors out). diff --git a/android/settings.gradle.kts b/android/settings.gradle.kts index 10d1422..0fb6c5a 100644 --- a/android/settings.gradle.kts +++ b/android/settings.gradle.kts @@ -1,8 +1,9 @@ pluginManagement { repositories { + google() gradlePluginPortal() mavenCentral() - // google() is only needed by the Android-framework modules (see below). + // google() (above) serves AGP for the Android-framework modules. // It requires the Android Gradle Plugin / SDK, absent in this env. } } @@ -12,6 +13,7 @@ dependencyResolutionManagement { // Modules must not declare their own repositories. repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) repositories { + google() mavenCentral() } // The version catalog at gradle/libs.versions.toml is auto-registered as `libs`. @@ -28,11 +30,14 @@ include(":client-tls") include(":test-support") // ── Android-framework modules ─────────────────────────────────────────────────── -// Scaffolded (dirs + build.gradle.kts stubs exist) but NOT included, because this -// environment has NO Android SDK. Their build scripts apply `com.android.*` -// plugins that cannot resolve here. -// TODO(android-sdk): enable when an Android SDK is available. -// include(":app") -// include(":terminal-view") -// include(":host-registry") -// include(":client-tls-android") +// The Android SDK IS now installed (see android/README.md → "Android SDK setup"), +// and AGP 9.2.1 is proven to build against SDK 35 with Gradle 9.6.1. These stay +// commented out only because their build.gradle.kts are still empty SCAFFOLD STUBS +// — enable each as its real module is implemented (plan AW2+). +// Recipe: apply `alias(libs.plugins.android.library)` ONLY (AGP 9 has built-in +// Kotlin — do NOT add kotlin.android); android { namespace; compileSdk = 35; +// defaultConfig { minSdk = 29 } }. +// include(":app") // AW4 — uses libs.plugins.android.application +// include(":terminal-view") // AW3 +// include(":host-registry") // AW1/AW2 storage half +// include(":client-tls-android") // AW1 framework half