Skip to content

Commit 72f919b

Browse files
authored
Add work around for updateLegacyAbi not updating Android API files. (#3325)
1 parent 09dab03 commit 72f919b

2 files changed

Lines changed: 69 additions & 38 deletions

File tree

build.gradle.kts

Lines changed: 66 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ allprojects {
133133

134134
if (project.name in publicModules) {
135135
configureAbiValidation()
136+
configureAndroidLegacyAbiValidation()
136137
}
137138

138139
// Skiko's runtime files are ESM-only so preload our shim to let Node require them during tests.
@@ -145,50 +146,80 @@ allprojects {
145146
}
146147
}
147148

148-
fun configureAbiValidation() {
149-
@OptIn(ExperimentalAbiValidation::class)
150-
fun Project.configureKotlinProject() {
151-
extensions.configure<KotlinProjectExtension> {
152-
fun AbiValidationVariantSpec.configure() = filters {
153-
excluded {
154-
annotatedWith.add("coil3.annotation.InternalCoilApi")
155-
}
156-
}
149+
@OptIn(ExperimentalAbiValidation::class)
150+
fun Project.configureAbiValidation() {
151+
afterEvaluate {
152+
val kotlinExtension = extensions.findByType<KotlinProjectExtension>() ?: return@afterEvaluate
157153

158-
// Unfortunately the 'enabled' property doesn't share a common interface.
159-
extensions.findByType<AbiValidationExtension>()?.apply {
160-
enabled = true
161-
configure()
162-
}
163-
extensions.findByType<AbiValidationMultiplatformExtension>()?.apply {
164-
enabled = true
165-
configure()
154+
fun AbiValidationVariantSpec.configureVariant() = filters {
155+
excluded {
156+
annotatedWith.add("coil3.annotation.InternalCoilApi")
166157
}
167158
}
168-
}
169159

170-
pluginManager.withPlugin("org.jetbrains.kotlin.multiplatform") {
171-
configureKotlinProject()
172-
}
173-
pluginManager.withPlugin("com.android.kotlin.multiplatform.library") {
174-
pluginManager.withPlugin("org.jetbrains.kotlin.multiplatform") {
175-
configureKotlinProject()
160+
// Unfortunately the 'enabled' property doesn't share a common interface.
161+
kotlinExtension.extensions.findByType<AbiValidationExtension>()?.apply {
162+
enabled.set(true)
163+
configureVariant()
164+
}
165+
kotlinExtension.extensions.findByType<AbiValidationMultiplatformExtension>()?.apply {
166+
enabled.set(true)
167+
configureVariant()
176168
}
177169
}
178-
pluginManager.withPlugin("org.jetbrains.kotlin.jvm") {
179-
configureKotlinProject()
180-
}
170+
}
181171

182-
// Built-in Kotlin Android wires the Kotlin extension during Android plugin application.
183-
pluginManager.withPlugin("com.android.application") {
184-
configureKotlinProject()
185-
}
186-
pluginManager.withPlugin("com.android.library") {
187-
configureKotlinProject()
172+
fun Project.configureAndroidLegacyAbiValidation() {
173+
plugins.withId("com.android.kotlin.multiplatform.library") {
174+
afterEvaluate {
175+
tasks
176+
.matching { it.name == "dumpLegacyAbi" || it.name.startsWith("dumpLegacyAbi") }
177+
.configureEach {
178+
tasks.findByName("compileAndroidMain")?.let { dependsOn(it) }
179+
configureAndroidLegacyAbiDumpInput(this@configureAndroidLegacyAbiValidation)
180+
}
181+
}
188182
}
189-
pluginManager.withPlugin("com.android.test") {
190-
configureKotlinProject()
183+
}
184+
185+
private fun Task.configureAndroidLegacyAbiDumpInput(project: Project) {
186+
val dumpTaskClass = javaClass
187+
val getJvm = runCatching { dumpTaskClass.getMethod("getJvm") }.getOrNull() ?: return
188+
val jvmProperty = getJvm.invoke(this)
189+
190+
val propertyClass = jvmProperty.javaClass
191+
val get = propertyClass.getMethod("get")
192+
val set = propertyClass.getMethod("set", Iterable::class.java)
193+
194+
val existingEntries = mutableListOf<Any>()
195+
val currentEntries = get.invoke(jvmProperty)
196+
if (currentEntries is Iterable<*>) {
197+
currentEntries.filterNotNullTo(existingEntries)
198+
} else {
199+
return
191200
}
201+
202+
val entryClass = existingEntries.firstOrNull()?.javaClass
203+
?: runCatching {
204+
dumpTaskClass.classLoader.loadClass(
205+
$$"org.jetbrains.kotlin.gradle.tasks.abi.KotlinLegacyAbiDumpTaskImpl$JvmTargetInfo",
206+
)
207+
}.getOrNull()
208+
?: return
209+
210+
val getSubdirectoryName = entryClass.getMethod("getSubdirectoryName")
211+
if (existingEntries.any { getSubdirectoryName.invoke(it) == "android" }) return
212+
213+
val constructor = entryClass.getConstructor(String::class.java, FileCollection::class.java)
214+
val androidClasses = project.files(
215+
project.layout.buildDirectory.dir("classes/kotlin/android/main"),
216+
project.layout.buildDirectory.dir("classes/java/android/main"),
217+
project.layout.buildDirectory.dir("intermediates/javac/androidMain/classes"),
218+
)
219+
val androidEntry = constructor.newInstance("android", androidClasses)
220+
221+
existingEntries.add(androidEntry)
222+
set.invoke(jvmProperty, existingEntries)
192223
}
193224

194225
private val ktlintRules = buildMap {

coil-core/api/android/coil-core.api

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -360,12 +360,12 @@ public final class coil3/decode/DecodeUtils {
360360
public static final field INSTANCE Lcoil3/decode/DecodeUtils;
361361
public static final fun calculateInSampleSize (IIIILcoil3/size/Scale;)I
362362
public static final fun computeDstSize-sEdh43o (IILcoil3/size/Size;Lcoil3/size/Scale;Lcoil3/size/Size;)J
363+
public static final fun computeSizeMultiplier (DDDDLcoil3/size/Scale;)D
363364
public static final fun computeSizeMultiplier (DDDDLcoil3/size/Scale;Lcoil3/size/Size;)D
365+
public static final fun computeSizeMultiplier (FFFFLcoil3/size/Scale;)F
364366
public static final fun computeSizeMultiplier (FFFFLcoil3/size/Scale;Lcoil3/size/Size;)F
367+
public static final fun computeSizeMultiplier (IIIILcoil3/size/Scale;)D
365368
public static final fun computeSizeMultiplier (IIIILcoil3/size/Scale;Lcoil3/size/Size;)D
366-
public static synthetic fun computeSizeMultiplier$default (DDDDLcoil3/size/Scale;Lcoil3/size/Size;ILjava/lang/Object;)D
367-
public static synthetic fun computeSizeMultiplier$default (FFFFLcoil3/size/Scale;Lcoil3/size/Size;ILjava/lang/Object;)F
368-
public static synthetic fun computeSizeMultiplier$default (IIIILcoil3/size/Scale;Lcoil3/size/Size;ILjava/lang/Object;)D
369369
}
370370

371371
public abstract interface class coil3/decode/Decoder {

0 commit comments

Comments
 (0)