Fix binary incompatibility with Android Gradle plugin 3.2.0-alpha06

Remove a non-reflective usage of the ResourceSet class, which has been
moved to a different package between versions. Access it through
reflection instead. This is a workaround. We can introduce a proper
fix once we have a public API in the Android plugin.

The test case that could detect the compatibility issue is
`testAndroidExtensionsManyVariants` (it uses experimental Android
extensions), but we did not run it with 3.2.0-alpha6. This commit
adds a test class with the same tests for 3.2.0-alpha6.

Issue #KT-23192 Fixed
This commit is contained in:
Sergey Igushkin
2018-03-13 20:56:59 +03:00
parent 3a7a34cc4e
commit 0039be6972
3 changed files with 26 additions and 11 deletions
@@ -13,7 +13,15 @@ import java.io.File
class KotlinAndroidGradleIT : AbstractKotlinAndroidGradleTests(gradleVersion = GradleVersionRequired.AtLeast("3.4"), androidGradlePluginVersion = "2.3.0")
class KotlinAndroidWithJackGradleIT : AbstractKotlinAndroidWithJackGradleTests(androidGradlePluginVersion = "2.3.+")
class KotlinAndroid30GradleIT : AbstractKotlinAndroidGradleTests(gradleVersion = GradleVersionRequired.AtLeast("4.1"), androidGradlePluginVersion = "3.0.0-beta1") {
// TODO If we there is a way to fetch the latest Android plugin version, test against the latest version
class KotlinAndroid32GradleIT : KotlinAndroid3GradleIT(GradleVersionRequired.AtLeast("4.5"), "3.2.0-alpha06")
class KotlinAndroid30GradleIT : KotlinAndroid3GradleIT(GradleVersionRequired.AtLeast("4.1"), "3.0.0")
abstract class KotlinAndroid3GradleIT(
gradleVersionRequired: GradleVersionRequired,
androidGradlePluginVersion: String
) : AbstractKotlinAndroidGradleTests(gradleVersionRequired, androidGradlePluginVersion) {
@Test
fun testApplyWithFeaturePlugin() {
@@ -314,5 +322,4 @@ abstract class AbstractKotlinAndroidWithJackGradleTests(
assertContains("Kotlin Gradle plugin does not support the deprecated Jack toolchain")
}
}
}
}
@@ -13,7 +13,7 @@ buildscript {
allprojects {
repositories {
mavenLocal()
mavenCentral()
jcenter()
maven { url 'https://maven.google.com' }
}
}
@@ -4,7 +4,6 @@ import com.android.build.gradle.*
import com.android.build.gradle.api.*
import com.android.build.gradle.tasks.MergeResources
import com.android.builder.model.SourceProvider
import com.android.ide.common.res2.ResourceSet
import org.gradle.api.Project
import org.gradle.api.file.FileCollection
import org.gradle.api.tasks.compile.AbstractCompile
@@ -120,7 +119,7 @@ class Android25ProjectHandler(kotlinConfigurationTools: KotlinConfigurationTools
}
override fun getResDirectories(variantData: BaseVariant): List<File> {
return variantData.mergeResources?.computeResourceSetList0()?.flatMap { it.sourceFiles } ?: emptyList()
return variantData.mergeResources?.computeResourceSetList0() ?: emptyList()
}
private inner class KaptVariant(variantData: BaseVariant) : KaptVariantData<BaseVariant>(variantData) {
@@ -143,17 +142,26 @@ class Android25ProjectHandler(kotlinConfigurationTools: KotlinConfigurationTools
}
}
//TODO once the Android plugin reaches its 3.0.0 release, consider compiling against it (remove the reflective call)
//TODO this is a private API for now
private fun MergeResources.computeResourceSetList0(): List<ResourceSet>? {
//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
val oldIsAccessible = computeResourceSetListMethod.isAccessible
try {
computeResourceSetListMethod.isAccessible = true
@Suppress("UNCHECKED_CAST")
return computeResourceSetListMethod.invoke(this) as? List<ResourceSet>
val resourceSets = computeResourceSetListMethod.invoke(this) as? Iterable<*>
return resourceSets
?.mapNotNull { resourceSet ->
val getSourceFiles = resourceSet?.javaClass?.methods?.find { it.name == "getSourceFiles" && it.parameterCount == 0 }
val files = getSourceFiles?.invoke(resourceSet)
@Suppress("UNCHECKED_CAST")
files as? Iterable<File>
}
?.flatten()
} finally {
computeResourceSetListMethod.isAccessible = oldIsAccessible
}