Drop support for Android Gradle plugin 2.x

#KT-27886 Fixed
This commit is contained in:
Alexey Tsvetkov
2018-10-30 06:47:40 +03:00
parent b51461b5c5
commit e9abd69fc0
9 changed files with 42 additions and 440 deletions
@@ -3,7 +3,6 @@ package org.jetbrains.kotlin.gradle
import org.gradle.api.logging.LogLevel
import org.jetbrains.kotlin.gradle.util.getFileByName
import org.jetbrains.kotlin.gradle.util.getFilesByNames
import org.jetbrains.kotlin.gradle.util.isLegacyAndroidGradleVersion
import org.jetbrains.kotlin.gradle.util.modify
import org.jetbrains.kotlin.test.KotlinTestUtils
import org.junit.Test
@@ -11,12 +10,6 @@ import java.io.File
import kotlin.test.assertEquals
import kotlin.test.assertTrue
class KotlinAndroidGradleIT : AbstractKotlinAndroidGradleTests(androidGradlePluginVersion = "2.3.0") {
override val defaultGradleVersion: GradleVersionRequired
get() = GradleVersionRequired.InRange("4.0", "4.10.2")
}
// TODO If we there is a way to fetch the latest Android plugin version, test against the latest version
class KotlinAndroid32GradleIT : KotlinAndroid3GradleIT(androidGradlePluginVersion = "3.2.0") {
override val defaultGradleVersion: GradleVersionRequired
@@ -491,11 +484,6 @@ fun getSomething() = 10
@Test
fun testAndroidExtensionsManyVariants() {
if (isLegacyAndroidGradleVersion(androidGradlePluginVersion)) {
// Library dependencies are not supported in older versions of Android Gradle plugin (< 3.0)
return
}
val project = Project("AndroidExtensionsManyVariants")
val options = defaultBuildOptions().copy(incremental = false)
@@ -555,16 +543,14 @@ fun getSomething() = 10
fun testMultiplatformAndroidCompile() = with(Project("multiplatformAndroidProject")) {
setupWorkingDir()
if (!isLegacyAndroidGradleVersion(androidGradlePluginVersion)) {
// Check that the common module is not added to the deprecated configuration 'compile' (KT-23719):
gradleBuildScript("libAndroid").appendText(
"""${'\n'}
// Check that the common module is not added to the deprecated configuration 'compile' (KT-23719):
gradleBuildScript("libAndroid").appendText(
"""${'\n'}
configurations.compile.dependencies.all { aDependencyExists ->
throw GradleException("Check failed")
}
""".trimIndent()
)
}
)
build("build") {
assertSuccessful()
@@ -1,7 +1,6 @@
package org.jetbrains.kotlin.gradle
import org.jetbrains.kotlin.gradle.util.getFileByName
import org.jetbrains.kotlin.gradle.util.isLegacyAndroidGradleVersion
import org.jetbrains.kotlin.gradle.util.modify
import org.jetbrains.kotlin.test.KotlinTestUtils
import org.junit.Test
@@ -21,7 +20,7 @@ open class Kapt3Android32IT : Kapt3AndroidIT() {
open class Kapt3AndroidIT : Kapt3BaseIT() {
protected open val androidGradlePluginVersion: String
get() = "2.3.0"
get() = "3.0.0"
override val defaultGradleVersion: GradleVersionRequired
get() = GradleVersionRequired.InRange("4.1", "4.10.2")
@@ -41,20 +40,11 @@ open class Kapt3AndroidIT : Kapt3BaseIT() {
assertKaptSuccessful()
assertFileExists("app/build/generated/source/kapt/debug/org/example/kotlin/butterknife/SimpleActivity\$\$ViewBinder.java")
val butterknifeJavaClassesDir =
if (isLegacyAndroidGradleVersion(androidGradlePluginVersion))
"app/build/intermediates/classes/debug/org/example/kotlin/butterknife/"
else
"app/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/org/example/kotlin/butterknife/"
val butterknifeJavaClassesDir = "app/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/org/example/kotlin/butterknife/"
assertFileExists(butterknifeJavaClassesDir + "SimpleActivity\$\$ViewBinder.class")
assertFileExists("app/build/tmp/kotlin-classes/debug/org/example/kotlin/butterknife/SimpleAdapter\$ViewHolder.class")
if (isLegacyAndroidGradleVersion(androidGradlePluginVersion)) {
// we don't copy classes with new AGP
assertFileExists("app/build/intermediates/classes/debug/org/example/kotlin/butterknife/SimpleAdapter\$ViewHolder.class")
}
}
project.build("assembleDebug") {
@@ -73,19 +63,11 @@ open class Kapt3AndroidIT : Kapt3BaseIT() {
assertFileExists("app/build/generated/source/kapt/debug/com/example/dagger/kotlin/DaggerApplicationComponent.java")
assertFileExists("app/build/generated/source/kapt/debug/com/example/dagger/kotlin/ui/HomeActivity_MembersInjector.java")
val daggerJavaClassesDir =
if (isLegacyAndroidGradleVersion(androidGradlePluginVersion))
"app/build/intermediates/classes/debug/com/example/dagger/kotlin/"
else
"app/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/example/dagger/kotlin/"
val daggerJavaClassesDir = "app/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/example/dagger/kotlin/"
assertFileExists(daggerJavaClassesDir + "DaggerApplicationComponent.class")
assertFileExists("app/build/tmp/kotlin-classes/debug/com/example/dagger/kotlin/AndroidModule.class")
if (isLegacyAndroidGradleVersion(androidGradlePluginVersion)) {
// we don't copy classes with new AGP
assertFileExists("app/build/intermediates/classes/debug/com/example/dagger/kotlin/AndroidModule.class")
}
}
}
@@ -154,29 +136,14 @@ open class Kapt3AndroidIT : Kapt3BaseIT() {
val project = Project("android-databinding", directoryPrefix = "kapt2")
setupDataBinding(project, "app")
if (isLegacyAndroidGradleVersion(androidGradlePluginVersion)) {
// Aapt from the older Android SDK crashes with the 'library' subproject structure.
project.projectDir.getFileByName("settings.gradle")
.modify {
assert(it.contains(", ':library'"))
it.replace(", ':library'", "")
}
}
project.build("assembleDebug", "assembleAndroidTest") {
assertSuccessful()
assertKaptSuccessful()
assertFileExists("app/build/generated/source/kapt/debug/com/example/databinding/BR.java")
if (!isLegacyAndroidGradleVersion(androidGradlePluginVersion)) {
assertFileExists("library/build/generated/source/kapt/debugAndroidTest/android/databinding/DataBinderMapperImpl.java")
}
assertFileExists("library/build/generated/source/kapt/debugAndroidTest/android/databinding/DataBinderMapperImpl.java")
if (isLegacyAndroidGradleVersion(androidGradlePluginVersion)) {
assertFileExists("app/build/generated/source/kapt/debug/com/example/databinding/databinding/ActivityTestBinding.java")
} else {
assertFileExists("app/build/generated/source/kapt/debug/com/example/databinding/databinding/ActivityTestBindingImpl.java")
}
assertFileExists("app/build/generated/source/kapt/debug/com/example/databinding/databinding/ActivityTestBindingImpl.java")
// KT-23866
assertNotContains("The following options were not recognized by any processor")
@@ -186,22 +153,20 @@ open class Kapt3AndroidIT : Kapt3BaseIT() {
private fun setupDataBinding(project: Project, projectName: String?) {
project.setupWorkingDir()
if (!isLegacyAndroidGradleVersion(androidGradlePluginVersion)) {
// With new AGP, there's no need in the Databinding kapt dependency:
project.gradleBuildScript(projectName).modify {
it.lines().filterNot {
it.contains("kapt \"com.android.databinding:compiler")
}.joinToString("\n")
}
// With new AGP, there's no need in the Databinding kapt dependency:
project.gradleBuildScript(projectName).modify {
it.lines().filterNot {
it.contains("kapt \"com.android.databinding:compiler")
}.joinToString("\n")
}
// Workaround for KT-24915
project.gradleBuildScript(projectName).appendText(
"\n" + """
// Workaround for KT-24915
project.gradleBuildScript(projectName).appendText(
"\n" + """
afterEvaluate {
kaptDebugKotlin.dependsOn dataBindingExportFeaturePackageIdsDebug
}
""".trimIndent()
)
}
)
}
}
@@ -1,6 +0,0 @@
package org.jetbrains.kotlin.gradle.util
import org.gradle.util.VersionNumber
fun isLegacyAndroidGradleVersion(androidGradlePluginVersion: String): Boolean =
VersionNumber.parse(androidGradlePluginVersion) < VersionNumber.parse("3.0.0-alpha1")
@@ -24,8 +24,6 @@ repositories {
google()
}
val agp25CompileOnly by configurations.creating
pill {
variant = PillExtension.Variant.FULL
}
@@ -61,13 +59,9 @@ dependencies {
runtime(project(":kotlin-reflect"))
// com.android.tools.build:gradle has ~50 unneeded transitive dependencies
agp25CompileOnly("com.android.tools.build:gradle:3.0.0-alpha1") { isTransitive = false }
agp25CompileOnly("com.android.tools.build:gradle-core:3.0.0-alpha1") { isTransitive = false }
agp25CompileOnly("com.android.tools.build:builder-model:3.0.0-alpha1") { isTransitive = false }
agp25CompileOnly("org.codehaus.groovy:groovy-all:2.4.12")
agp25CompileOnly(gradleApi())
agp25CompileOnly(project(":kotlin-annotation-processing"))
agp25CompileOnly(project(":kotlin-annotation-processing-gradle"))
compileOnly("com.android.tools.build:gradle:3.0.0") { isTransitive = false }
compileOnly("com.android.tools.build:gradle-core:3.0.0") { isTransitive = false }
compileOnly("com.android.tools.build:builder-model:3.0.0") { isTransitive = false }
testCompileOnly (project(":compiler"))
testCompile(projectTests(":kotlin-build-common"))
@@ -80,9 +74,6 @@ dependencies {
testCompileOnly(project(":kotlin-annotation-processing-gradle"))
}
val agp25 by sourceSets.creating
agp25.compileClasspath += configurations.compile + agp25CompileOnly + mainSourceSet.output
tasks {
withType<KotlinCompile> {
kotlinOptions.jdkHome = rootProject.extra["JDK_18"] as String
@@ -100,8 +91,6 @@ tasks {
}
named<Jar>("jar") {
dependsOn(tasks.named("agp25Classes"))
from(agp25.output.classesDirs)
callGroovy("manifestAttributes", manifest, project)
}
@@ -248,16 +248,11 @@ class AndroidSubplugin : KotlinGradleSubplugin<KotlinCompile> {
return wrapPluginOptions(pluginOptions, "configuration")
}
// Android25ProjectHandler.KaptVariant actually contains BaseVariant, not BaseVariantData
private fun getVariantComponentNames(flavorData: Any?): VariantComponentNames? = when (flavorData) {
is KaptVariantData<*> -> getVariantComponentNames(flavorData.variantData)
is TestVariantData -> getVariantComponentNames(flavorData.testedVariantData)
is TestVariant -> getVariantComponentNames(flavorData.testedVariant)
is BaseVariant -> VariantComponentNames(flavorData.name, flavorData.flavorName, flavorData.buildType.name)
is BaseVariantData<*> -> VariantComponentNames(
flavorData.name, flavorData.variantConfiguration.flavorName,
flavorData.variantConfiguration.buildType.name
)
else -> null
}
@@ -603,7 +603,7 @@ internal open class KotlinAndroidPlugin(
val version = loadAndroidPluginVersion()
if (version != null) {
val minimalVersion = "1.1.0"
val minimalVersion = "3.0.0"
if (compareVersionNumbers(version, minimalVersion) < 0) {
throw IllegalStateException("Kotlin: Unsupported version of com.android.tools.build:gradle plugin: version $minimalVersion or higher should be used with kotlin-android plugin")
}
@@ -614,17 +614,7 @@ internal open class KotlinAndroidPlugin(
kotlinPluginVersion
)
val legacyVersionThreshold = "2.5.0"
return if (compareVersionNumbers(version, legacyVersionThreshold) < 0) {
LegacyAndroidAndroidProjectHandler(kotlinTools)
} else {
val android25ProjectHandlerClass = Class.forName("org.jetbrains.kotlin.gradle.plugin.Android25ProjectHandler")
val ctor = android25ProjectHandlerClass.constructors.single {
it.parameterTypes.contentEquals(arrayOf(kotlinTools.javaClass))
}
ctor.newInstance(kotlinTools) as AbstractAndroidProjectHandler<*>
}
return Android25ProjectHandler(kotlinTools)
}
fun applyToTarget(
@@ -641,9 +631,6 @@ class KotlinConfigurationTools internal constructor(
val kotlinPluginVersion: String
)
/** Part of Android configuration, that works only with the old public API.
* @see [LegacyAndroidAndroidProjectHandler] that is implemented with the old internal API and [AndroidGradle25VariantProcessor] that works
* with the new public API */
abstract class AbstractAndroidProjectHandler<V>(private val kotlinConfigurationTools: KotlinConfigurationTools) {
protected val logger = Logging.getLogger(this.javaClass)
@@ -1,155 +0,0 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.gradle.plugin
import com.android.build.gradle.BaseExtension
import com.android.build.gradle.BasePlugin
import com.android.build.gradle.internal.variant.BaseVariantData
import com.android.build.gradle.internal.variant.BaseVariantOutputData
import com.android.build.gradle.internal.variant.LibraryVariantData
import com.android.build.gradle.internal.variant.TestVariantData
import com.android.builder.model.SourceProvider
import org.gradle.api.Project
import org.gradle.api.ProjectConfigurationException
import org.gradle.api.file.FileCollection
import org.gradle.api.tasks.bundling.AbstractArchiveTask
import org.gradle.api.tasks.compile.AbstractCompile
import org.jetbrains.kotlin.gradle.internal.KaptTask
import org.jetbrains.kotlin.gradle.internal.KaptVariantData
import org.jetbrains.kotlin.gradle.internal.registerGeneratedJavaSource
import org.jetbrains.kotlin.gradle.logging.kotlinDebug
import org.jetbrains.kotlin.gradle.plugin.android.AndroidGradleWrapper
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJvmAndroidCompilation
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import org.jetbrains.kotlin.gradle.utils.checkedReflection
import java.io.File
import java.util.concurrent.Callable
internal class LegacyAndroidAndroidProjectHandler(kotlinConfigurationTools: KotlinConfigurationTools) :
AbstractAndroidProjectHandler<BaseVariantData<out BaseVariantOutputData>>(kotlinConfigurationTools) {
override fun getSourceProviders(variantData: BaseVariantData<out BaseVariantOutputData>): Iterable<SourceProvider> =
variantData.sourceProviders
override fun getAllJavaSources(variantData: BaseVariantData<out BaseVariantOutputData>): Iterable<File> =
AndroidGradleWrapper.getJavaSources(variantData)
override fun forEachVariant(project: Project, action: (BaseVariantData<out BaseVariantOutputData>) -> Unit) {
val plugin = (project.plugins.findPlugin("android")
?: project.plugins.findPlugin("android-library")
?: project.plugins.findPlugin("com.android.test")) as BasePlugin
val variantManager = AndroidGradleWrapper.getVariantDataManager(plugin)
variantManager.variantDataList.forEach(action)
}
override fun getLibraryOutputTask(variant: BaseVariantData<out BaseVariantOutputData>): AbstractArchiveTask? =
null // We don't support publishing AARs of old Android in MPP
override fun wireKotlinTasks(
project: Project,
compilation: KotlinJvmAndroidCompilation,
androidPlugin: BasePlugin,
androidExt: BaseExtension,
variantData: BaseVariantData<out BaseVariantOutputData>,
javaTask: AbstractCompile,
kotlinTask: KotlinCompile
) {
kotlinTask.dependsOn(*javaTask.dependsOn.toTypedArray())
kotlinTask.mapClasspath {
javaTask.classpath + project.files(AndroidGradleWrapper.getRuntimeJars(androidPlugin, androidExt))
}
configureJavaTask(kotlinTask, javaTask, logger)
// In lib modules, the androidTest variants get the classes jar in their classpath instead of the Java
// destination dir. Attach the JAR to be consumed as friend path:
if (variantData is LibraryVariantData) {
variantData.dependencyJarOrNull?.let { jar -> kotlinTask.attachClassesDir { jar } }
}
}
private val LibraryVariantData.dependencyJarOrNull: File?
get() =
checkedReflection(f@{
val output = variantConfiguration.javaClass.methods.firstOrNull { it.name == "getOutput" }
?.invoke(variantConfiguration)
?: return@f null
output.javaClass.methods?.firstOrNull { it.name == "getJarFile" }
?.invoke(output) as? File
}, { e: Exception ->
logger.kotlinDebug("dependencyJarOrNull for lib variant $name failed due to $e")
null
})
override fun getVariantName(variant: BaseVariantData<out BaseVariantOutputData>): String = variant.name
private fun operationNotSupportedInOldAndroidPlugin(): Nothing =
throw UnsupportedOperationException("Publishing is not supported for Android Gradle plugin 2.3.x and below. Please upgrade to 3.0+")
override fun getFlavorNames(variant: BaseVariantData<out BaseVariantOutputData>): List<String> =
operationNotSupportedInOldAndroidPlugin()
override fun getBuildTypeName(variant: BaseVariantData<out BaseVariantOutputData>): String =
operationNotSupportedInOldAndroidPlugin()
override fun checkVariantIsValid(variant: BaseVariantData<out BaseVariantOutputData>) {
if (AndroidGradleWrapper.isJackEnabled(variant)) {
throw ProjectConfigurationException(
"Kotlin Gradle plugin does not support the deprecated Jack toolchain.\n" +
"Disable Jack or revert to Kotlin Gradle plugin version 1.1.1.", null
)
}
}
override fun getJavaTask(variantData: BaseVariantData<out BaseVariantOutputData>): AbstractCompile? =
AndroidGradleWrapper.getJavaTask(variantData)
override fun addJavaSourceDirectoryToVariantModel(
variantData: BaseVariantData<out BaseVariantOutputData>,
javaSourceDirectory: File
) =
variantData.addJavaSourceFoldersToModel(javaSourceDirectory)
override fun getTestedVariantData(variantData: BaseVariantData<*>): BaseVariantData<*>? =
((variantData as? TestVariantData)?.testedVariantData as? BaseVariantData<*>)
override fun getResDirectories(variantData: BaseVariantData<out BaseVariantOutputData>): FileCollection {
val project = variantData.mergeResourcesTask.project
return project.files(
Callable { variantData.mergeResourcesTask?.rawInputFolders?.toList().orEmpty() }
)
}
private val BaseVariantData<*>.sourceProviders: List<SourceProvider>
get() = variantConfiguration.sortedSourceProviders
private inner class KaptLegacyVariantData(variantData: BaseVariantData<out BaseVariantOutputData>) :
KaptVariantData<BaseVariantData<out BaseVariantOutputData>>(variantData) {
override val name: String = variantData.name
override val sourceProviders: Iterable<SourceProvider> = getSourceProviders(variantData)
override fun addJavaSourceFoldersToModel(generatedFilesDir: File) =
addJavaSourceDirectoryToVariantModel(variantData, generatedFilesDir)
override val annotationProcessorOptions: Map<String, String>? =
AndroidGradleWrapper.getAnnotationProcessorOptionsFromAndroidVariant(variantData)
override fun registerGeneratedJavaSource(
project: Project,
kaptTask: KaptTask,
javaTask: AbstractCompile
) {
registerGeneratedJavaSource(kaptTask, javaTask)
}
}
override fun wrapVariantDataForKapt(variantData: BaseVariantData<out BaseVariantOutputData>)
: KaptVariantData<BaseVariantData<out BaseVariantOutputData>> =
KaptLegacyVariantData(variantData)
}
@@ -1,3 +1,8 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.gradle.plugin
import com.android.build.gradle.*
@@ -18,9 +23,9 @@ import org.jetbrains.kotlin.gradle.utils.addExtendsFromRelation
import java.io.File
import java.util.concurrent.Callable
@Suppress("unused")
class Android25ProjectHandler(kotlinConfigurationTools: KotlinConfigurationTools)
: AbstractAndroidProjectHandler<BaseVariant>(kotlinConfigurationTools) {
class Android25ProjectHandler(
kotlinConfigurationTools: KotlinConfigurationTools
) : AbstractAndroidProjectHandler<BaseVariant>(kotlinConfigurationTools) {
override fun forEachVariant(project: Project, action: (BaseVariant) -> Unit) {
val androidExtension = project.extensions.getByName("android")
@@ -70,17 +75,17 @@ class Android25ProjectHandler(kotlinConfigurationTools: KotlinConfigurationTools
// Find the classpath entries that comes from the tested variant and register it as the friend path, lazily
kotlinTask.friendPaths = lazy {
variantData.getCompileClasspathArtifacts(preJavaClasspathKey)
.filter { it.id.componentIdentifier is TestedComponentIdentifier }
.map { it.file.absolutePath }
.toTypedArray()
.filter { it.id.componentIdentifier is TestedComponentIdentifier }
.map { it.file.absolutePath }
.toTypedArray()
}
}
override fun getSourceProviders(variantData: BaseVariant): Iterable<SourceProvider> =
variantData.sourceSets
variantData.sourceSets
override fun getAllJavaSources(variantData: BaseVariant): Iterable<File> =
variantData.getSourceFolders(SourceKind.JAVA).map { it.dir }
variantData.getSourceFolders(SourceKind.JAVA).map { it.dir }
override fun getVariantName(variant: BaseVariant): String = variant.name
@@ -105,7 +110,7 @@ class Android25ProjectHandler(kotlinConfigurationTools: KotlinConfigurationTools
}
override fun addJavaSourceDirectoryToVariantModel(variantData: BaseVariant, javaSourceDirectory: File) =
variantData.addJavaSourceFoldersToModel(javaSourceDirectory)
variantData.addJavaSourceFoldersToModel(javaSourceDirectory)
override fun getResDirectories(variantData: BaseVariant): FileCollection {
val getAllResourcesMethod =
@@ -150,10 +155,10 @@ class Android25ProjectHandler(kotlinConfigurationTools: KotlinConfigurationTools
override val name: String = getVariantName(variantData)
override val sourceProviders: Iterable<SourceProvider> = getSourceProviders(variantData)
override fun addJavaSourceFoldersToModel(generatedFilesDir: File) =
addJavaSourceDirectoryToVariantModel(variantData, generatedFilesDir)
addJavaSourceDirectoryToVariantModel(variantData, generatedFilesDir)
override val annotationProcessorOptions: Map<String, String>? =
variantData.javaCompileOptions.annotationProcessorOptions.arguments
variantData.javaCompileOptions.annotationProcessorOptions.arguments
override fun registerGeneratedJavaSource(
project: Project,
@@ -178,7 +183,7 @@ class Android25ProjectHandler(kotlinConfigurationTools: KotlinConfigurationTools
//TODO A public API is expected for this purpose. Once it is available, use the public API
private fun MergeResources.computeResourceSetList0(): List<File>? {
val computeResourceSetListMethod = MergeResources::class.java.declaredMethods
.firstOrNull { it.name == "computeResourceSetList" && it.parameterCount == 0 } ?: return null
.firstOrNull { it.name == "computeResourceSetList" && it.parameterCount == 0 } ?: return null
val oldIsAccessible = computeResourceSetListMethod.isAccessible
try {
@@ -208,5 +213,5 @@ class Android25ProjectHandler(kotlinConfigurationTools: KotlinConfigurationTools
?.invoke(this) as? FileCollection
override fun wrapVariantDataForKapt(variantData: BaseVariant): KaptVariantData<BaseVariant> =
KaptVariant(variantData)
KaptVariant(variantData)
}
@@ -7,13 +7,6 @@ package org.jetbrains.kotlin.gradle.plugin.android
import com.android.build.gradle.BaseExtension
import com.android.build.gradle.BasePlugin
import com.android.build.gradle.api.AndroidSourceSet
import com.android.build.gradle.internal.VariantManager
import com.android.build.gradle.internal.variant.BaseVariantData
import org.gradle.api.file.ConfigurableFileTree
import org.gradle.api.tasks.compile.AbstractCompile
import java.io.File
import java.lang.reflect.Field
import java.lang.reflect.InvocationTargetException
import java.lang.reflect.Method
import java.lang.reflect.Modifier
@@ -22,138 +15,6 @@ object AndroidGradleWrapper {
fun getRuntimeJars(basePlugin: BasePlugin, baseExtension: BaseExtension): Any? {
return basePlugin("getRuntimeJarList") ?: baseExtension("getBootClasspath") ?: basePlugin("getBootClasspath")
}
fun isJackEnabled(variantData: Any): Boolean {
val variantConfiguration = variantData("getVariantConfiguration")
return (variantConfiguration("getUseJack") ?: variantConfiguration("getJackOptions")("isEnabled")) as? Boolean ?: false
}
fun getJavaTask(variantData: Any): AbstractCompile? {
return getJavaCompile(variantData)
}
private fun getJavaCompile(baseVariantData: Any): AbstractCompile? {
return (baseVariantData["javaCompileTask"] ?: baseVariantData["javaCompilerTask"]) as? AbstractCompile
}
fun getAnnotationProcessorOptionsFromAndroidVariant(variantData: Any?): Map<String, String>? {
if (variantData !is BaseVariantData<*>) {
throw IllegalArgumentException("BaseVariantData instance expected")
}
val compileOptions = variantData("getVariantConfiguration")("getJavaCompileOptions") ?: return null
@Suppress("UNCHECKED_CAST")
return compileOptions("getAnnotationProcessorOptions")("getArguments") as? Map<String, String>
}
fun getVariantDataManager(plugin: BasePlugin): VariantManager {
return plugin("getVariantManager") as VariantManager
}
fun getJavaSources(variantData: BaseVariantData<*>): List<File> {
val result = LinkedHashSet<File>()
// user sources
for (provider in variantData.variantConfiguration.sortedSourceProviders) {
result.addAll((provider as AndroidSourceSet).java.srcDirs)
}
// generated sources
val javaSources = variantData("getJavaSources")
if (javaSources is Array<*>) {
result += javaSources.filterIsInstance<File>()
} else if (javaSources is List<*>) {
val fileTrees = javaSources.filterIsInstance<ConfigurableFileTree>()
result += fileTrees.map { it.dir }
} else {
if (variantData.scope.generateRClassTask != null) {
result += variantData.scope.rClassSourceOutputDir
}
if (variantData.scope.generateBuildConfigTask != null) {
result += variantData.scope.buildConfigSourceOutputDir
}
if (variantData.scope.aidlCompileTask != null) {
result += variantData.scope.aidlSourceOutputDir
}
if (variantData.scope.globalScope.extension.dataBinding.isEnabled) {
result += variantData.scope.classOutputForDataBinding
}
if (!variantData.variantConfiguration.renderscriptNdkModeEnabled && variantData.scope.renderscriptCompileTask != null) {
result += variantData.scope.renderscriptSourceOutputDir
}
}
val extraSources = variantData("getExtraGeneratedSourceFolders") as? List<*>
if (extraSources != null) {
result += extraSources.filterIsInstance<File>()
}
return result.toList()
}
fun getJarToAarMapping(variantData: BaseVariantData<*>): Map<File, File> {
val jarToLibraryArtifactMap = hashMapOf<File, File>()
val libraries = getVariantLibraryDependencies(variantData) ?: return jarToLibraryArtifactMap
for (lib in libraries) {
lib ?: continue
val bundle = getLibraryArtifactFile(lib) ?: continue
val libJarFile = lib("getJarFile") as? File ?: continue
jarToLibraryArtifactMap[libJarFile] = bundle
@Suppress("UNCHECKED_CAST")
val localJarsForLib = lib("getLocalJars") as? List<*> ?: emptyList<Any>()
// local dependencies are detected as changed by gradle, because they are seem to be
// rewritten every time when bundle changes
// when local dep will actually change, record for bundle will be removed from registry
for (localDep in localJarsForLib) {
if (localDep is File) {
// android tools 2.2
jarToLibraryArtifactMap[localDep] = bundle
} else {
// android tools < 2.2
val jarFile = localDep("getJarFile") as? File ?: continue
jarToLibraryArtifactMap[jarFile] = bundle
}
}
}
return jarToLibraryArtifactMap
}
private fun getLibraryArtifactFile(lib: Any): File? {
return if (lib.javaClass.name == "com.android.builder.dependency.level2.AndroidDependency") {
// android tools >= 2.3
lib("getArtifactFile") as? File
} else {
// android tools <= 2.2
lib("getBundle") as? File
}
}
private fun getVariantLibraryDependencies(variantData: BaseVariantData<*>): Iterable<*>? {
val variantDependency = variantData.variantDependency
variantDependency("getAndroidDependencies")?.let {
// android tools < 2.2
return it as Iterable<*>
}
val compileDependencies = variantDependency("getCompileDependencies") ?: return null
val result = compileDependencies("getDirectAndroidDependencies") // android >= 2.3
?: compileDependencies("getAndroidDependencies") // android 2.2
return result as? Iterable<*>
}
}
private operator fun Any?.invoke(methodName: String): Any? {
@@ -178,29 +39,4 @@ private operator fun Any?.invoke(methodName: String): Any? {
} finally {
methodToInvoke.isAccessible = oldIsAccessible
}
}
private operator fun Any?.get(name: String): Any? {
if (this == null) {
return null
}
this.invoke("get" + name.capitalize())?.let { return it }
fun Array<Field>.findField() = singleOrNull { it.name == name && !Modifier.isStatic(it.modifiers) }
val clazz = this::class.java
val fieldToInvoke = clazz.declaredFields.findField() ?: clazz.fields.findField() ?: return null
val oldIsAccessible = fieldToInvoke.isAccessible
try {
fieldToInvoke.isAccessible = true
return fieldToInvoke.get(this)
} catch (e: InvocationTargetException) {
throw e.targetException
} catch (e: Throwable) {
throw RuntimeException("Couldn't get value of field '$name' in $this", e)
} finally {
fieldToInvoke.isAccessible = oldIsAccessible
}
}