Use kotlinOptions for Android extension (CommonExtension) in Gradle convention plugin

Hello there,

I’m working with Gradle convention plugins because I would like to have some sort of baseline configuration for all my modules, most of them are Android ones, I’m trying to create some sort of base Android convention that would be reused by two other convention plugins more specialized, dedicated for Android library modules and Android application modules.

I struggling a little bit with this “base” convention plugin of mine, it is mostly AGP but I have issues with kotlin-android part of it, it looks like that:

import com.android.build.api.dsl.ApplicationDefaultConfig
import com.android.build.api.dsl.ApplicationExtension
import com.android.build.api.dsl.CommonExtension
import com.android.build.api.dsl.DefaultConfig
import com.android.build.api.dsl.LibraryDefaultConfig
import com.android.build.api.dsl.LibraryExtension

plugins {
    id("com.android.base")
    kotlin("android")
    id("org.jetbrains.kotlin.plugin.parcelize")
}

android {
    compileSdk = 31

    defaultConfig {
        minSdk = AndroidConfig.minSdkVersion
        targetSdk = AndroidConfig.targetSdkVersion
        consumerProguardFile("proguard-rules.pro")
    }

    sourceSets {
        val sourceSet = getByName("main")
        sourceSet.res.srcDir("${project.buildDir}/generated/res/custom")
    }

    lint {
        warning.addAll(
            listOf(
                "InvalidPackage",
                "ExtraTranslation",
                "MissingTranslation",
                "ResourceType",
                "ImpliedQuantity",
                // Added due to Lint improperly reporting missing "many" for FR locale
                "MissingQuantity"
            )
        )
        disable.add("TypographyEllipsis")
    }

    compileOptions {
        sourceCompatibility = JavaConfig.sourceCompatibility
        targetCompatibility = JavaConfig.targetCompatibility
    }

    /*
    kotlinOptions {
        jvmTarget = KotlinConfig.jvmTarget
    }
     */

    buildFeatures {
        viewBinding = true
    }
}

// --------------- Below this line is mumbo-jumbo that allows us to have this nice format above ---------------

/**
 * Creates special [android] function at the top that mimics usual android section, configure blocks are looking for
 * extensions, Android plugins should not overlap, we are looking for extensions to find out which plugin is applied
 */
fun android(block: CommonExtension<*, *, *, *>.() -> Unit) {
    extensions.findByType<ApplicationExtension>()?.apply {
        block.invoke(this)
    }
    extensions.findByType<LibraryExtension>()?.apply {
        block.invoke(this)
    }
}

/**
 * Delegate properties passing value to correct implementations
 */
var DefaultConfig.targetSdk: Int?
    get() = 0
    set(newValue) {
        when (this) {
            is ApplicationDefaultConfig -> this.targetSdk = newValue
            is LibraryDefaultConfig -> this.targetSdk = newValue
            else -> {
                // it is possible that more might be need here
            }
        }
    }

fun DefaultConfig.consumerProguardFile(proguardFile: Any): Any {
    return when (this) {
        is LibraryDefaultConfig -> this.consumerProguardFile(proguardFile)
        else -> {
            // ignore
        }
    }
}

I cannot find the way how to setup kotlinOptions which is now commented out

Doing that in Groovy is simpler since it’s not using generated accessors etc. do yourself a favour and use Groovy, you will save hours of pointless work