From 9d6cf01194442f34eea99e54837b584021aab6b4 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Tue, 25 Nov 2025 12:38:55 -0700 Subject: [PATCH 1/2] Add support for AGP 9 This adds a convenience compat class that supports backwards compatibility as well as support for LibraryExtension, which will he required with AGP9. Upgrading to AGP 9 will also require extension developers to replace BaseExtension in the `Project.android` declaration with LibraryExtension, and also replace `compileSdkVersion` with `compileSdk` outside of `defaultConfig`, as well as move `targetSdk` to a new lint block, and remove `apply(plugin = "kotlin-android")` since AGP 9 has built-in Kotlin, that is no longer supported. This should have no affecf for those that don't upgrade to AGP 9, or those you don't decide to use LibraryExtension in AGP 8 which is also supported. --- .../gradle/LibraryExtensionCompat.kt | 79 +++++++++++++++++++ .../gradle/tasks/CompileDexTask.kt | 7 +- .../gradle/tasks/CompileResourcesTask.kt | 6 +- .../gradle/tasks/DeployWithAdbTask.kt | 6 +- .../cloudstream3/gradle/tasks/Tasks.kt | 6 +- 5 files changed, 91 insertions(+), 13 deletions(-) create mode 100644 src/main/kotlin/com/lagradost/cloudstream3/gradle/LibraryExtensionCompat.kt diff --git a/src/main/kotlin/com/lagradost/cloudstream3/gradle/LibraryExtensionCompat.kt b/src/main/kotlin/com/lagradost/cloudstream3/gradle/LibraryExtensionCompat.kt new file mode 100644 index 0000000..23cbc94 --- /dev/null +++ b/src/main/kotlin/com/lagradost/cloudstream3/gradle/LibraryExtensionCompat.kt @@ -0,0 +1,79 @@ +package com.lagradost.cloudstream3.gradle + +import com.android.build.gradle.BaseExtension +import com.android.build.api.dsl.LibraryExtension +import com.android.build.api.variant.LibraryAndroidComponentsExtension +import org.gradle.api.Project +import java.io.File + +/** + * Compatibility layer for AGP 9, maintaining backward compatibility with AGP 8 + * for Android library modules. Provides access to necessary properties, + * in a way that works across both versions. + * + * Support for BaseExtension can be removed once support for AGP 8 is no longer required. + */ +internal class LibraryExtensionCompat(private val project: Project) { + + private val android = project.extensions.findByName("android") + ?: error("Android plugin not found") + + val compileSdk: String + get() = when (android) { + is BaseExtension -> android.compileSdkVersion ?: error("compileSdkVersion not found") + is LibraryExtension -> "android-${android.compileSdk}" + else -> error("Android plugin found, but it's not a library module") + } + + val minSdk: Int + get() = when (android) { + is BaseExtension -> android.defaultConfig.minSdk ?: 21 + is LibraryExtension -> android.defaultConfig.minSdk ?: 21 + else -> error("Android plugin found, but it's not a library module") + } + + val buildToolsVersion: String + get() = when (android) { + is BaseExtension -> android.buildToolsVersion + is LibraryExtension -> android.buildToolsVersion + else -> error("Android plugin found, but it's not a library module") + } + + val adb: File + get() = when (android) { + is BaseExtension -> android.adbExecutable + is LibraryExtension -> project.extensions + .findByType(LibraryAndroidComponentsExtension::class.java) + ?.sdkComponents + ?.adb?.get()?.asFile ?: error("LibraryAndroidComponentsExtension not found") + else -> error("Unknown Android extension type") + } + + val bootClasspath: Any + get() = when (android) { + is BaseExtension -> android.bootClasspath + is LibraryExtension -> project.extensions + .findByType(LibraryAndroidComponentsExtension::class.java) + ?.sdkComponents + ?.bootClasspath ?: error("LibraryAndroidComponentsExtension not found") + else -> error("Unknown Android extension type") + } + + val sdkDirectory: File + get() = when (android) { + is BaseExtension -> android.sdkDirectory + is LibraryExtension -> project.extensions + .findByType(LibraryAndroidComponentsExtension::class.java) + ?.sdkComponents + ?.sdkDirectory + ?.get()?.asFile ?: error("LibraryAndroidComponentsExtension not found") + else -> error("Unknown Android extension type") + } + + val mainResSrcDir: File + get() = when (android) { + is BaseExtension -> android.sourceSets.getByName("main").res.srcDirs.single() + is LibraryExtension -> project.layout.projectDirectory.dir("src/main/res").asFile + else -> error("Unknown Android extension type") + } +} diff --git a/src/main/kotlin/com/lagradost/cloudstream3/gradle/tasks/CompileDexTask.kt b/src/main/kotlin/com/lagradost/cloudstream3/gradle/tasks/CompileDexTask.kt index 37d4104..b87d3ec 100644 --- a/src/main/kotlin/com/lagradost/cloudstream3/gradle/tasks/CompileDexTask.kt +++ b/src/main/kotlin/com/lagradost/cloudstream3/gradle/tasks/CompileDexTask.kt @@ -1,7 +1,7 @@ package com.lagradost.cloudstream3.gradle.tasks +import com.lagradost.cloudstream3.gradle.LibraryExtensionCompat import com.lagradost.cloudstream3.gradle.getCloudstream -import com.android.build.gradle.BaseExtension import com.android.build.gradle.internal.errors.MessageReceiverImpl import com.android.build.gradle.options.SyncOptions.ErrorFormatMode import com.android.builder.dexing.ClassFileInputs @@ -35,9 +35,8 @@ abstract class CompileDexTask : DefaultTask() { @TaskAction fun compileDex() { - val android = project.extensions.getByName("android") as BaseExtension - - val minSdk = android.defaultConfig.minSdk ?: 21 + val android = LibraryExtensionCompat(project) + val minSdk = android.minSdk val dexOutputDir = outputFile.get().asFile.parentFile diff --git a/src/main/kotlin/com/lagradost/cloudstream3/gradle/tasks/CompileResourcesTask.kt b/src/main/kotlin/com/lagradost/cloudstream3/gradle/tasks/CompileResourcesTask.kt index b697465..c09d209 100644 --- a/src/main/kotlin/com/lagradost/cloudstream3/gradle/tasks/CompileResourcesTask.kt +++ b/src/main/kotlin/com/lagradost/cloudstream3/gradle/tasks/CompileResourcesTask.kt @@ -1,6 +1,6 @@ package com.lagradost.cloudstream3.gradle.tasks -import com.android.build.gradle.BaseExtension +import com.lagradost.cloudstream3.gradle.LibraryExtensionCompat import org.gradle.api.file.DirectoryProperty import org.gradle.api.file.RegularFileProperty import org.gradle.api.tasks.* @@ -20,7 +20,7 @@ abstract class CompileResourcesTask : Exec() { abstract val outputFile: RegularFileProperty override fun exec() { - val android = project.extensions.getByName("android") as BaseExtension + val android = LibraryExtensionCompat(project) val aaptExecutable = android.sdkDirectory.resolve("build-tools") .resolve(android.buildToolsVersion) @@ -44,7 +44,7 @@ abstract class CompileResourcesTask : Exec() { "-I", android.sdkDirectory .resolve("platforms") - .resolve(android.compileSdkVersion!!) + .resolve(android.compileSdk) .resolve("android.jar") ) args("-R", tmpRes.path) diff --git a/src/main/kotlin/com/lagradost/cloudstream3/gradle/tasks/DeployWithAdbTask.kt b/src/main/kotlin/com/lagradost/cloudstream3/gradle/tasks/DeployWithAdbTask.kt index bdb4f81..42a9780 100644 --- a/src/main/kotlin/com/lagradost/cloudstream3/gradle/tasks/DeployWithAdbTask.kt +++ b/src/main/kotlin/com/lagradost/cloudstream3/gradle/tasks/DeployWithAdbTask.kt @@ -1,7 +1,7 @@ package com.lagradost.cloudstream3.gradle.tasks +import com.lagradost.cloudstream3.gradle.LibraryExtensionCompat import com.lagradost.cloudstream3.gradle.getCloudstream -import com.android.build.gradle.BaseExtension import org.gradle.api.DefaultTask import org.gradle.api.tasks.AbstractCopyTask import org.gradle.api.tasks.Input @@ -17,9 +17,9 @@ abstract class DeployWithAdbTask : DefaultTask() { @TaskAction fun deployWithAdb() { - val android = project.extensions.getByName("android") as BaseExtension + val android = LibraryExtensionCompat(project) - AdbServerLauncher(Subprocess(), android.adbExecutable.absolutePath).launch() + AdbServerLauncher(Subprocess(), android.adb.absolutePath).launch() val jadbConnection = JadbConnection() val devices = jadbConnection.devices.filter { try { diff --git a/src/main/kotlin/com/lagradost/cloudstream3/gradle/tasks/Tasks.kt b/src/main/kotlin/com/lagradost/cloudstream3/gradle/tasks/Tasks.kt index a2048d9..35b5269 100644 --- a/src/main/kotlin/com/lagradost/cloudstream3/gradle/tasks/Tasks.kt +++ b/src/main/kotlin/com/lagradost/cloudstream3/gradle/tasks/Tasks.kt @@ -1,8 +1,8 @@ package com.lagradost.cloudstream3.gradle.tasks +import com.lagradost.cloudstream3.gradle.LibraryExtensionCompat import com.lagradost.cloudstream3.gradle.getCloudstream import com.lagradost.cloudstream3.gradle.makeManifest -import com.android.build.gradle.BaseExtension import com.android.build.gradle.tasks.ProcessLibraryManifest import groovy.json.JsonBuilder import groovy.json.JsonGenerator @@ -67,8 +67,8 @@ fun registerTasks(project: Project) { project.tasks.getByName("processDebugManifest") as ProcessLibraryManifest it.dependsOn(processManifestTask) - val android = project.extensions.getByName("android") as BaseExtension - it.input.set(android.sourceSets.getByName("main").res.srcDirs.single()) + val android = LibraryExtensionCompat(project) + it.input.set(android.mainResSrcDir) it.manifestFile.set(processManifestTask.manifestOutputFile) it.outputFile.set(intermediates.resolve("res.apk")) From cd882212c3f426ed6e75af5e18835996f5f8ad3d Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Wed, 26 Nov 2025 18:53:34 -0700 Subject: [PATCH 2/2] Better error message --- .../cloudstream3/gradle/LibraryExtensionCompat.kt | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/com/lagradost/cloudstream3/gradle/LibraryExtensionCompat.kt b/src/main/kotlin/com/lagradost/cloudstream3/gradle/LibraryExtensionCompat.kt index 23cbc94..7e1ad5a 100644 --- a/src/main/kotlin/com/lagradost/cloudstream3/gradle/LibraryExtensionCompat.kt +++ b/src/main/kotlin/com/lagradost/cloudstream3/gradle/LibraryExtensionCompat.kt @@ -73,7 +73,17 @@ internal class LibraryExtensionCompat(private val project: Project) { val mainResSrcDir: File get() = when (android) { is BaseExtension -> android.sourceSets.getByName("main").res.srcDirs.single() - is LibraryExtension -> project.layout.projectDirectory.dir("src/main/res").asFile + is LibraryExtension -> { + val dir = project.layout.projectDirectory.dir("src/main/res").asFile + if (!dir.exists()) { + error( + "Resource directory not found at ${dir.path}. " + + "Resources are only supported in src/main/res. " + + "If this extension has no resources, remove requiresResources = true." + ) + } + dir + } else -> error("Unknown Android extension type") } }