This message was deleted.
# general
s
This message was deleted.
t
have you tried applying your plugin via
plugins { ... }
?
v
Two things to note: 1. You could directly do
project.apply
instead of
project.pluginManager.apply
2. You only get type-safe accessors for plugins you apply using the
plugins { }
DSL. Using the legacy API you use to apply your own plugin does not work for that. If you insist on applying your custom plugin the legacy way, you have to use the cumbersome way for configuring extensions like
configure<WhateverClassTheAndroidExtensionWas> { ... }
instead of
android { ... }
. But preferable is to apply your custom plugin using the
plugins { }
dsl
a
@tony yes, makes no differences
v
Your custom plugin, right? Not the android and kotlin plugins. Can you show how you tried?
a
@Vampire So I can’t “hide” the Android Gradle Plugin inside my own custom plugin? The end goal is to be able to just apply my plugin in 1 line which will: • Apply any plugin we use in all libraries • Configure their DSL inside that plugin
v
Of course you can, where did I say you cannot?
til 1
a
@Vampire Yes my own plugin, just a sec I’ll bring some code here
👌 1
Here’s the full plugin, which gives you an idea what I want to do:
Copy code
open class ConvenientLibraryPlugin : Plugin<Project> {

    @Suppress("UNCHECKED_CAST")
    override fun apply(project: Project) {

        project.plugins.apply("com.android.library")
        project.plugins.apply("org.jetbrains.kotlin.android")
        
        // first test
        val androidComponents = project.extensions.getByType(AndroidComponentsExtension::class.java)
        androidComponents.finalizeDsl { extension ->
            extension.apply {
                compileSdk = 31
                defaultConfig.apply {
                    minSdk = 23
                    // targetSdk = 31 <- Unknown here
                    testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
                    //consumerProguardFiles("<http://consumer-rules.pro|consumer-rules.pro>") <- Unknown here
                }
            }
        }
        
        // second try getting the extension and setting the DSL here
        val extension = project.extensions.getByName("android")
        val libraryExtension = extension as AndroidComponentsExtension<LibraryExtension, LibraryVariantBuilder, LibraryVariant>

        libraryExtension.finalizeDsl { extension ->
            extension.apply {
                compileSdk = 31
                defaultConfig.apply {
                    minSdk = 23
                    targetSdk = 31
                    testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
                    consumerProguardFiles("<http://consumer-rules.pro|consumer-rules.pro>")
                }
            }
        }
    }
}
I don’t like the direct casting to
AndroidComponentsExtension<LibraryExtension, LibraryVariantBuilder, LibraryVariant>
if you’re asking me, but couldn’t find a way to get the right object out of
project.extensions
and here’s where I am testing that, in a
build.gradle.kts
:
Copy code
apply<il.co.galex.convenience.plugin.ConvenientLibraryPlugin>()

android {

    buildTypes {
        release {
            isMinifyEnabled = false
            proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "<http://proguard-rules.pro|proguard-rules.pro>")
        }
    }
    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_1_8
        targetCompatibility = JavaVersion.VERSION_1_8
    }
    kotlinOptions {
        jvmTarget = "1.8"
    }
}

dependencies {

    implementation("androidx.core:core-ktx:1.7.0")
    implementation("androidx.appcompat:appcompat:1.3.0")
    implementation("com.google.android.material:material:1.4.0")
    testImplementation("junit:junit:4.13.2")
    androidTestImplementation("androidx.test.ext:junit:1.1.3")
    androidTestImplementation("androidx.test.espresso:espresso-core:3.4.0")
}
@Vampire I do hope I can still set some values in the
android {}
extension there, but I’d like to setup the common ones for many modules in the Gradle Plugin itself
v
You still use the legacy way to apply your plugin. As I said, when using the legacy
apply()
way, then you don't get accessors like
android { ... }
. You need to apply your plugin using the
plugins { ... }
DSL to get those accessors generated as described above. Within your plugin, you should not use
project.plugins.apply
, but
project.apply
as also written above. Within your plugin, you can do
configure<AndroidComponentsExtension<LibraryExtension, LibraryVariantBuilder, LibraryVariant>> { ... }
to get the extension by type without the need to cast as also already described above. If you want to do
android { ... }
within your plugin, you have to either create that accessor yourself, of you have to switch from a full Kotlin class plugin to a precompiled script plugin. Those are looking almost exactly like normal build scripts and there you also get the accessors generated.
a
Wow thanks so much for this info, I’ll take a while to try/digest this, thank you 👍
👌 1
@Vampire Thank you Björn so much for your help, I am finally getting somewhere! Here’s the whole
build.gradle
:
Copy code
plugins {
    id("il.co.galex.library")
}

dependencies {

    implementation("androidx.core:core-ktx:1.7.0")
    implementation("androidx.appcompat:appcompat:1.3.0")
    implementation("com.google.android.material:material:1.4.0")
    testImplementation("junit:junit:4.13.2")
    androidTestImplementation("androidx.test.ext:junit:1.1.3")
    androidTestImplementation("androidx.test.espresso:espresso-core:3.4.0")
}
And here is the Gradle Plugin:
Copy code
open class ConvenientLibraryPlugin : Plugin<Project> {

    override fun apply(project: Project) {

        with(project) {

            apply {
                it.plugin("com.android.library")
                it.plugin("org.jetbrains.kotlin.android")
            }

            extensions.configure(LibraryExtension::class.java) { libExtension ->
                libExtension.apply {
                    compileSdk = 31

                    defaultConfig {
                        minSdk = 23
                        targetSdk = 31

                        testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
                        consumerProguardFiles("<http://consumer-rules.pro|consumer-rules.pro>")
                    }

                    buildTypes {
                        release {
                            isMinifyEnabled = false
                            proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "<http://proguard-rules.pro|proguard-rules.pro>")
                        }
                    }

                    compileOptions {
                        sourceCompatibility = JavaVersion.VERSION_1_8
                        targetCompatibility = JavaVersion.VERSION_1_8
                    }

                    // doesn't work
//                    kotlinOptions {
//                        jvmTarget = "1.8"
//                    }
                }
            }
        }
    }
}
So the only missing piece is how do I get to have a
kotlinOptions
in that extension? I guess it has to do with importing the
gradle-plugin
and configuring the tasks of type
KotlinCompile
maybe?
v
The same as said before.
kotlinOptions
is an accessor that you don't get generated for that type of plugins. So you again use a
configure
call with type. So what you want is probably this:
Copy code
import com.android.build.api.dsl.LibraryExtension
import org.gradle.api.JavaVersion
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.kotlin.dsl.apply
import org.gradle.kotlin.dsl.configure
import org.jetbrains.kotlin.gradle.dsl.KotlinCommonOptions
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmOptions

open class ConvenientLibraryPlugin : Plugin<Project> {
    override fun apply(project: Project) {
        with(project) {
            apply(plugin = "com.android.library")
            apply(plugin = "org.jetbrains.kotlin.android")

            configure<LibraryExtension> {
                compileSdk = 31

                defaultConfig {
                    minSdk = 23
                    targetSdk = 31

                    testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
                    consumerProguardFiles("<http://consumer-rules.pro|consumer-rules.pro>")
                }

                buildTypes {
                    release {
                        isMinifyEnabled = false
                        proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "<http://proguard-rules.pro|proguard-rules.pro>")
                    }
                }

                compileOptions {
                    sourceCompatibility = JavaVersion.VERSION_1_8
                    targetCompatibility = JavaVersion.VERSION_1_8
                }

                configure<KotlinJvmOptions> {
                    jvmTarget = "1.8"
                }
            }
        }
    }
}
👍 1
p
@Alexander Gherschon its documented here https://docs.gradle.org/current/userguide/kotlin_dsl.html#type-safe-accessors
Consider the sample build script shown above that demonstrates the use of type-safe accessors. The following sample is exactly the same except that is uses the 
apply()
 method to apply the plugin. The build script can not use type-safe accessors in this case because the 
apply()
 call happens in the body of the build script. You have to use other techniques instead, as demonstrated here:
👍 1
a
Thank you @Vampire and @Paul Blundell 😊