From 9ce76cb47194365e7d53ac9a13230958777382f7 Mon Sep 17 00:00:00 2001 From: Daniel Alome Date: Mon, 10 Aug 2026 14:48:48 +0100 Subject: [PATCH 1/4] ADFA-2602: Correct version references in plugin docs and metadata comments PLUGIN_AUTHORING.md told plugin authors to request AGP 8.11.0 and Kotlin 1.9.22 for an on-device build. The harvested localMvnRepository now ships AGP 9.3.1 and Kotlin 2.3.21, so those instructions produced an unresolvable build. The apiVersion/languageVersion pins in common, eventbus-events, idetooltips and plugin-api stay at 2.0. Their comments named 1.9.22 as the reason, which no longer holds; the real invariant is that the jar must stay readable by every supported on-device compiler, including a device still on an older bundled toolchain after a KOTLIN_VERSION bump. Reworded to say that instead of naming a version that will keep going stale. --- common/build.gradle.kts | 2 +- docs/PLUGIN_AUTHORING.md | 6 +++--- eventbus-events/build.gradle.kts | 2 +- idetooltips/build.gradle.kts | 2 +- plugin-api/build.gradle.kts | 3 ++- 5 files changed, 8 insertions(+), 7 deletions(-) diff --git a/common/build.gradle.kts b/common/build.gradle.kts index dc01fac8e9..8ef2d82734 100755 --- a/common/build.gradle.kts +++ b/common/build.gradle.kts @@ -12,7 +12,7 @@ android { kotlin { compilerOptions { // This module's classes ship in the plugin-api coordinate that on-device plugins - // compile against, so emit metadata the on-device Kotlin (1.9.22) can read (<= 2.0.0). + // compile against, so emit metadata every supported on-device Kotlin can read (<= 2.0.0). apiVersion.set(org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_2_0) languageVersion.set(org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_2_0) } diff --git a/docs/PLUGIN_AUTHORING.md b/docs/PLUGIN_AUTHORING.md index 7b7d4610fd..a3314398cd 100644 --- a/docs/PLUGIN_AUTHORING.md +++ b/docs/PLUGIN_AUTHORING.md @@ -71,7 +71,7 @@ injected `com.itsaky.androidide.plugins.build` `1.0.0` marker. The `plugins {}` example above uses AGP `8.8.2` / Kotlin `2.1.21` — the versions the dev/CI repo resolves online. A plugin built **on-device** resolves AGP and the Kotlin Gradle plugin from the harvested on-device `localMvnRepository`, which currently ships -only **AGP `8.11.0`** and **Kotlin `1.9.22`**. Request those versions for an on-device +only **AGP `8.13.1`** and **Kotlin `2.3.0`**. Request those versions for an on-device build, or offline resolution of the build plugins fails. Also declare AGP `apply false` in the **root** `build.gradle.kts` (as the standard CoGo @@ -79,8 +79,8 @@ project template does): ```kotlin plugins { - id("com.android.application") apply false version "8.11.0" - id("com.android.library") apply false version "8.11.0" + id("com.android.application") apply false version "8.13.1" + id("com.android.library") apply false version "8.13.1" } ``` diff --git a/eventbus-events/build.gradle.kts b/eventbus-events/build.gradle.kts index ac7acb7999..5bcb9d0cda 100644 --- a/eventbus-events/build.gradle.kts +++ b/eventbus-events/build.gradle.kts @@ -29,7 +29,7 @@ android { kotlin { compilerOptions { // This module's classes ship in the plugin-api coordinate that on-device plugins - // compile against, so emit metadata the on-device Kotlin (1.9.22) can read (<= 2.0.0). + // compile against, so emit metadata every supported on-device Kotlin can read (<= 2.0.0). apiVersion.set(org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_2_0) languageVersion.set(org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_2_0) } diff --git a/idetooltips/build.gradle.kts b/idetooltips/build.gradle.kts index 4716486943..98e9d2a70c 100644 --- a/idetooltips/build.gradle.kts +++ b/idetooltips/build.gradle.kts @@ -13,7 +13,7 @@ android { kotlin { compilerOptions { // This module's classes ship in the plugin-api coordinate that on-device plugins - // compile against, so emit metadata the on-device Kotlin (1.9.22) can read (<= 2.0.0). + // compile against, so emit metadata every supported on-device Kotlin can read (<= 2.0.0). apiVersion.set(org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_2_0) languageVersion.set(org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_2_0) } diff --git a/plugin-api/build.gradle.kts b/plugin-api/build.gradle.kts index a7943ce23c..f0e7b94eb7 100644 --- a/plugin-api/build.gradle.kts +++ b/plugin-api/build.gradle.kts @@ -22,7 +22,8 @@ android { kotlin { compilerOptions { jvmTarget.set(org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_17) - // Emit metadata the on-device Kotlin compiler (1.9.22) can read (<= 2.0.0). + // Emit metadata every supported on-device Kotlin compiler can read (<= 2.0.0), so a + // device still on an older bundled toolchain keeps working after a KOTLIN_VERSION bump. // This jar ships in the plugin-api coordinate on-device plugins compile against. apiVersion.set(org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_2_0) languageVersion.set(org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_2_0) From fc4a3924c1bcd8d24ec8393a73fef4fa0327e3d1 Mon Sep 17 00:00:00 2001 From: Daniel Alome Date: Wed, 19 Aug 2026 10:47:45 +0100 Subject: [PATCH 2/4] ADFA-2602: Point plugin docs at org.adfa.constants for on-device versions The on-device localMvnRepository ships AGP 9.3.1, Gradle 9.6.1 and Kotlin 2.3.21, not AGP 8.13.1 / Kotlin 2.3.0. AGP 9 also refuses org.jetbrains.kotlin.android and takes its compiler from the kotlin-gradle-plugin jar on the root buildscript classpath, so the documented root snippet would have failed to configure. Name the constants that pin these versions, so the doc stops going stale on every bump rather than being corrected after the fact. --- docs/PLUGIN_AUTHORING.md | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/docs/PLUGIN_AUTHORING.md b/docs/PLUGIN_AUTHORING.md index a3314398cd..82b9819749 100644 --- a/docs/PLUGIN_AUTHORING.md +++ b/docs/PLUGIN_AUTHORING.md @@ -39,7 +39,7 @@ in `build.gradle.kts`: ```kotlin plugins { id("com.android.application") version "8.8.2" - id("org.jetbrains.kotlin.android") version "2.1.21" + id("org.jetbrains.kotlin.android") version "2.3.0" id("com.itsaky.androidide.plugins.build") } @@ -66,21 +66,31 @@ against — the `:plugin-api` module plus `common`, `eventbus-events`, and `idetooltips`. The builder plugin applied above resolves the same way, from the injected `com.itsaky.androidide.plugins.build` `1.0.0` marker. -#### Building on-device (offline) pins the AGP/Kotlin versions +#### Building on-device (offline) pins the AGP/Kotlin/Gradle versions -The `plugins {}` example above uses AGP `8.8.2` / Kotlin `2.1.21` — the versions the -dev/CI repo resolves online. A plugin built **on-device** resolves AGP and the Kotlin -Gradle plugin from the harvested on-device `localMvnRepository`, which currently ships -only **AGP `8.13.1`** and **Kotlin `2.3.0`**. Request those versions for an on-device -build, or offline resolution of the build plugins fails. +The `plugins {}` example above uses AGP `8.8.2` / Kotlin `2.3.0` — the versions the +dev/CI repo resolves online. A plugin built **on-device** resolves its build plugins from +the harvested on-device `localMvnRepository`, which ships only the versions pinned in +`org.adfa.constants` — `ANDROID_GRADLE_PLUGIN_VERSION`, `KOTLIN_VERSION` and +`GRADLE_DISTRIBUTION_VERSION`, currently **AGP `9.3.1`**, **Kotlin `2.3.21`** and +**Gradle `9.6.1`**. Request those, or offline resolution of the build plugins fails. That +constants file is authoritative; the numbers here are a snapshot of it. -Also declare AGP `apply false` in the **root** `build.gradle.kts` (as the standard CoGo -project template does): +AGP 9 compiles Kotlin itself and **refuses** the `org.jetbrains.kotlin.android` plugin, so +an on-device build drops it and pins Kotlin through the `kotlin-gradle-plugin` jar on the +**root** buildscript classpath, which is where AGP 9 takes its compiler from. Declare AGP +`apply false` in the same root file (as the standard CoGo project template does): ```kotlin +buildscript { + dependencies { + classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:2.3.21") + } +} + plugins { - id("com.android.application") apply false version "8.13.1" - id("com.android.library") apply false version "8.13.1" + id("com.android.application") apply false version "9.3.1" + id("com.android.library") apply false version "9.3.1" } ``` From e35dd5ff298a4e3884d53c9adfdea2549db0258d Mon Sep 17 00:00:00 2001 From: Daniel Alome Date: Mon, 24 Aug 2026 16:41:32 +0100 Subject: [PATCH 3/4] ADFA-2602: Point the on-device SDK at build-tools 36.0.0 AGP 9.3.1 hard-requires build-tools >= 36.0.0, so `BUILD_TOOLS_VERSION` moves to 36.0.0. This drives `BUILD_TOOLS_DIR` and therefore the `android.aapt2FromMavenOverride` path that GradleBuildService passes to every build. This must land together with an asset that actually contains `build-tools/36.0.0`; on its own it points the IDE at a directory that does not exist yet. The matching dev-assets pipeline change and the platform-tools port that builds those binaries from android-16.0.0_r4 are the other two pieces. Also drop the build-tools version from the suppressed aapt2 warning. That entry is matched with `contains()` against the full override path, so pinning 35.0.0 meant the bump would silently stop matching and resurface an experimental-option warning in Build Output on every user build. Claude-Session: https://claude.ai/code/session_017HGpMsUzZ5wxCfMtDZ2HGP --- .../main/java/com/itsaky/androidide/ui/EditorBottomSheet.kt | 5 ++++- .../main/java/com/itsaky/androidide/utils/Environment.java | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/itsaky/androidide/ui/EditorBottomSheet.kt b/app/src/main/java/com/itsaky/androidide/ui/EditorBottomSheet.kt index 7bcce2b991..e6d32f6b3e 100644 --- a/app/src/main/java/com/itsaky/androidide/ui/EditorBottomSheet.kt +++ b/app/src/main/java/com/itsaky/androidide/ui/EditorBottomSheet.kt @@ -519,7 +519,10 @@ class EditorBottomSheet private val suppressedGradleWarnings = listOf( - "The option setting 'android.aapt2FromMavenOverride=/data/data/com.itsaky.androidide/files/home/android-sdk/build-tools/35.0.0/aapt2' is experimental", + // Matched with contains(), so the build-tools version is deliberately left + // out: the path moves with Environment.BUILD_TOOLS_VERSION and a hardcoded + // version silently stops matching, resurfacing the warning to users. + "The option setting 'android.aapt2FromMavenOverride=", "The org.gradle.api.plugins.BasePluginConvention type has been deprecated.", "The org.gradle.api.plugins.Convention type has been deprecated.", "The BasePluginExtension.archivesBaseName property has been deprecated.", diff --git a/common/src/main/java/com/itsaky/androidide/utils/Environment.java b/common/src/main/java/com/itsaky/androidide/utils/Environment.java index 9b7df27341..ce5e1f0db9 100755 --- a/common/src/main/java/com/itsaky/androidide/utils/Environment.java +++ b/common/src/main/java/com/itsaky/androidide/utils/Environment.java @@ -46,7 +46,7 @@ public final class Environment { private static final String ANDROIDIDE_PROJECT_CACHE_DIR = SharedEnvironment.PROJECT_CACHE_DIR_NAME; private static final String DATABASE_NAME = "documentation.db"; - public static final String BUILD_TOOLS_VERSION = "35.0.0"; + public static final String BUILD_TOOLS_VERSION = "36.0.0"; public static final String PLUGIN_API_JAR_RELATIVE_PATH = "libs/plugin-api.jar"; From 22184eb4845e9e42e4454d5b96e6ec092ef807ed Mon Sep 17 00:00:00 2001 From: Daniel Alome Date: Tue, 25 Aug 2026 19:45:25 +0100 Subject: [PATCH 4/4] ADFA-3078: Search the on-device Maven repo before the remote ones Offline builds failed unless the user turned on the --offline flag, which defeats the point of an offline-first IDE. The on-device repo was registered last. Templates declare gradlePluginPortal(), google() and mavenCentral() first, and this plugin appended with `maven { it.url = uri }`. With no network, dl.google.com fails DNS, and Gradle treats a repository *error* as fatal rather than falling through to the next repository the way it does for a 404. Resolution therefore died at google() and never reached the local repo. --offline worked only because it skips remote repositories entirely. The artifacts were never missing: the AGP plugin marker, kotlin-build-tools-compat and kotlin-build-tools-impl are all present in localMvnRepository on device. Inserting at index 0 instead of appending fixes all four injection points (pluginManagement, dependencyResolutionManagement, and the settings and project buildscript blocks). Verified on a Pixel 9 Pro emulator in airplane mode with offlineMode=false, the Gradle modules-2 cache deleted, and a brand new Empty Activity Kotlin project whose settings.gradle.kts was left untouched: sync reaches "Project initialized" and the build produces app-debug.apk. Both failed under identical conditions before this change. A warm module cache masks the bug, so retests need the cache cleared. Ships in the APK, not the assets zip, so no asset rebuild is required. Claude-Session: https://claude.ai/code/session_017HGpMsUzZ5wxCfMtDZ2HGP --- .../itsaky/androidide/gradle/COTGSettingsPlugin.kt | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/gradle-plugin/src/main/java/com/itsaky/androidide/gradle/COTGSettingsPlugin.kt b/gradle-plugin/src/main/java/com/itsaky/androidide/gradle/COTGSettingsPlugin.kt index 554592b627..37ded2903d 100644 --- a/gradle-plugin/src/main/java/com/itsaky/androidide/gradle/COTGSettingsPlugin.kt +++ b/gradle-plugin/src/main/java/com/itsaky/androidide/gradle/COTGSettingsPlugin.kt @@ -116,8 +116,13 @@ private fun RepositoryHandler.addMavenRepoIfMissing( logger: Logger, uri: URI, ) { - if (none { it is MavenArtifactRepository && it.url == uri }) { - logger.info("Adding maven repository: $uri") - maven { it.url = uri } + if (any { it is MavenArtifactRepository && it.url == uri }) { + return } + + logger.info("Adding maven repository: $uri") + val repo = maven { it.url = uri } + + remove(repo) + add(0, repo) }