@@ -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
194225private val ktlintRules = buildMap {
0 commit comments