How to properly call groovy gradle method from kotlin dsl - android

I have separate groovy script that adds flavors to my android project. And i can apply it no problem in build.gradle files. But calling it from kotlin build.gradle.kts file im getting error.
I have flavors.gradle file
ext.configFlavors = {
flavorDimensions "brand"
productFlavors {
myBrand {
dimension "brand"
}
}
And i can easilly call this from build.gradle files
android{
...
with configFlavors
}
But in build.gradle.kts files i get:
Could not find method flavorDimensions() for arguments [brand] on project ': myModule' of type org.gradle.api.Project.
My build.gradle.kts looks like this:
import com.android.build.gradle.LibraryExtension
plugins {
id("com.android.library")
id("org.jetbrains.kotlin.android")
}
apply(from ="${rootProject.projectDir}/buildSrc/flavors.gradle" )
val configFlavors: groovy.lang.Closure<LibraryExtension> by extra
android {
compileSdk = Versions.compile_sdk_version
defaultConfig {
minSdk = Versions.min_sdk_version
targetSdk = Versions.target_sdk_version
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles("consumer-rules.pro")
}
buildTypes {
//Dev
create("dev") {
isMinifyEnabled = false
proguardFiles(getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro")
}
//Staging
create("staging") {
isMinifyEnabled = false
proguardFiles(getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro")
}
//Production
create("production") {
isMinifyEnabled = false
proguardFiles(getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro")
}
}
// I am able to call the closure but i got the error
configFlavors()
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = "1.8"
}
buildFeatures {
viewBinding = true
}
}
dependencies {
implementation(fileTree("include" to listOf("*.jar"), "dir" to "libs"))
implementation(project(":domain"))
// list of dependencies
}

Extra properties can be accessed with the following syntax:
// get an extra property from the current project
val myProperty: String by extra
// or from the root project
val myNewProperty: String by rootProject.extra
However, configFlavours is not a simple primitive value, it's a Closure.
It's possible to access Closures in Kotlin, but without knowing what type the Closure should apply to, it's not possible to use it.
// Replace `Any` with the actual type, if known
val configFlavours: groovy.lang.Closure<Any> by extra
println(configFlavours)
// > Configure project :
// flavours_atn69ibjqzvnwf0cp7hb75l45$_run_closure1#398b577e
There are more through examples in the Gradle docs
P.S. your code has both flavour and flavor - pick a spelling please :)

I ended up adding another closure that takes libraryExtension as parameter. And using it from gradle.build.kts files. It is not optimal but it seems to work.
ext.configFlavorsWithParam = { libraryExtension ->
libraryExtension.flavorDimensions "brand"
libraryExtension.productFlavors {
brand1 {
dimension "brand"
}
}
And im calling it like this
android{
...
configFlavorsWithParam(this)
}

Related

How to make android and spring to exists together as modules in one project?

:) Last days I did some kotlin projects just for fun. Every project was created in kotlin as web app (spring) and mobile (android). I started to wondering if there is possibility to configure multimodule project where spring and android can be stored together as modules? I read some articles about multimodule projects but usually about web apps only. I tried doing something on my own but and nothing worked ;p
Here are my gradle files:
setting.gradle.kts (spring web)
rootProject.name = "web"
build.gradle.kts (spring web)
plugins {
id("org.springframework.boot") version "3.0.1"
id("io.spring.dependency-management") version "1.1.0"
kotlin("jvm") version "1.7.22"
kotlin("plugin.spring") version "1.7.22"
kotlin("plugin.jpa") version "1.7.22"
}
group = "pl.mattiahit.myrestaurant.web"
version = "0.0.1-SNAPSHOT"
java.sourceCompatibility = JavaVersion.VERSION_17
repositories {
mavenCentral()
}
dependencies {
implementation("org.springframework.boot:spring-boot-starter-data-jpa")
implementation("org.springframework.boot:spring-boot-starter-validation")
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
implementation("org.modelmapper:modelmapper:3.1.1")
implementation("org.jetbrains.kotlin:kotlin-reflect")
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
runtimeOnly("org.mariadb.jdbc:mariadb-java-client")
testImplementation("org.springframework.boot:spring-boot-starter-test")
}
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {
kotlinOptions {
freeCompilerArgs = listOf("-Xjsr305=strict")
jvmTarget = "17"
}
}
tasks.withType<Test> {
useJUnitPlatform()
}
build.gradle.kts (android)
plugins {
id("com.android.application")
id("org.jetbrains.kotlin.android")
}
android {
namespace = "pl.mattiahit.myrestaurant.mobile"
compileSdk = 32
defaultConfig {
applicationId = "pl.mattiahit.myrestaurant.mobile"
minSdk = 24
targetSdk = 32
versionCode = 1
versionName = "1.0"
testInstrumentationRunner = "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
isMinifyEnabled = false
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = "1.8"
}
}
dependencies {
implementation("com.android.support:appcompat-v7:28.0.0")
implementation("com.android.support.constraint:constraint-layout:2.0.4")
testImplementation("junit:junit:4.13.2")
androidTestImplementation("com.android.support.test:runner:1.0.2")
androidTestImplementation("com.android.support.test.espresso:espresso-core:3.0.2")
}
settings.gradle.kts (parent)
rootProject.name = "MyRestaurant"
include("web")
include("mobile")
build.gradle.kts (parent)
buildscript {
dependencies {
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.8.0")
}
}
Im getting error
A problem occurred configuring root project 'MyRestaurant'.
> Could not resolve all files for configuration ':classpath'.
> Cannot resolve external dependency org.jetbrains.kotlin:kotlin-gradle-plugin:1.8.0 because no repositories are defined.
Required by:
project :
I have no experience with such projects... can anyone help me with that? Is there any good article about mulimodule projects etc ?
As the error implies, you're missing the repositories block inside your top-level ("parent") build.gradle.kts:
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.8.0")
}
}

SourceSet with name 'main' not found

I'd like to Maven publish in my Android app, and I'm using kotlin-dsl for gradle files. This is how I'm trying to publish my code:
subprojects {
plugins.apply("maven-publish")
afterEvaluate {
// Common settings
if (isAndroidLibrary || isAndroidApplication) {
extensions.getByType<com.android.build.gradle.BaseExtension>().apply {
compileSdkVersion(CommonVersions.targetsdk)
buildToolsVersion = CommonVersions.buildTools
defaultConfig {
minSdkVersion(CommonVersions.minsdk)
targetSdkVersion(CommonVersions.targetsdk)
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
buildFeatures.viewBinding = true
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {
kotlinOptions {
jvmTarget = "1.8"
}
}
}
}
// Set up publishing configuration
val sourceSets: SourceSetContainer by project
print("project name: $name, ")
print("project size: ${sourceSets.size}, ")
print("project size: ${project.the<SourceSetContainer>().size}, ")
print("project size: ${the<SourceSetContainer>().size}, ")
if (!notPublishingModules.contains(name) && sourceSets.size != 0) {
configure<PublishingExtension> {
publications {
create<MavenPublication>("maven") {
groupId = "xx.yyy.zz"
artifactId = "test"
version = "0.0.0"
from(components.findByName("release"))
val sourcesJar by tasks.creating(Jar::class) {
val sourceSets: SourceSetContainer by project
from(sourceSets["main"].allJava)
classifier = "sources"
}
artifact(sourcesJar)
}
}
}
}
}
}
I always get this error: SourceSet with name 'main' not found.
As you can see I was trying to print the sourceset out, to see if it has any information or not. The size of the sourceset is always zero.
What am I doing wrong?
I use groovy with spring applications , I think you missing this in your code
sourceSets {
main {
java { srcDirs = ["src/java"] }
resources { srcDir "src/resources" }
}
}
where you define where is srcDirs are .

Android Library seems to loose some informations upon compilation

I was writing my own navigation for compose, by that ive created a seperate project that contains the library. after some time i could reuse the project in an compose desktop application. after some time i recieved emails about my project not running on andoid anymore. ive got this stacktrace: (other versions results in othewr method names but everytime method not found)
No virtual method setUi(Lkotlin/jvm/functions/Function5;)V in class Lcom/nom/rougthnav/ScreenConfiguration; or its super classes (declaration of 'com.nom.rougthnav.ScreenConfiguration' appears in /data/data/com.nom.myapplication/code_cache/.overlay/base.apk/classes.dex)
at com.nom.myapplication.MainActivity$onCreate$1$1$1$router$2$1.invoke(MainActivity.kt:33)
at com.nom.myapplication.MainActivity$onCreate$1$1$1$router$2$1.invoke(MainActivity.kt:31)
at com.nom.rougthnav.Router.screen(Router.kt:75)
at com.nom.rougthnav.Router.screen(Router.kt:47)
this keeps appearing only if i use this as an aar library, so ive researched about this.
ive analyzed my aar files and the final apk that got installed everywhere is the method present and i have no dependency version conflict. if i use the files directly in those projects its working like a charm.
ive thought that this might be resolved if i use another set of dependencies, so ive created a new sample project barely used anything, but got this error again in any version of my aar file.
an example:
ive got this interface for the configuration:
interface RouterScope<K> {
fun <T> screen(
tag: K,
modelFactory: () -> T,
block: #Composable (model: T, back: Back, nav: Nav<K>) -> Unit
)
var initialTag: K
var link: String
fun route(tag: K, initial: K, block: RouterScope<K>.() -> Unit)
var tagConverter: ((String) -> K)?
}
but the screen method keeps disappearing. im wondering if this is linked with the composeable annotation. But the composeable annotation is used the same way in other android libs.
Any hint appreciated, im finally stuck. here is my build.gradle.kts:
plugins {
id("org.jetbrains.kotlin.android")
id("com.android.library")
`maven-publish`
}
android {
compileSdk = 30
defaultConfig {
// applicationId = "com.nom.rougthnav"
minSdk = 27
targetSdk = 30
// versionCode = 1
// versionName = "1.0"
version = "1.6"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
isMinifyEnabled = false
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
kotlinOptions {
jvmTarget = "11"
}
}
dependencies {
implementation("androidx.core:core-ktx:1.6.0")
implementation("androidx.appcompat:appcompat:1.3.1")
implementation("com.google.android.material:material:1.4.0")
val compose = "1.0.3"
implementation("androidx.compose.ui:ui:$compose")
implementation("androidx.compose.ui:ui-tooling-preview:$compose")
implementation("androidx.compose.ui:ui-tooling:$compose")
testImplementation("junit:junit:4.13.2")
androidTestImplementation("androidx.test.ext:junit:1.1.3")
androidTestImplementation("androidx.test.espresso:espresso-core:3.4.0")
}
afterEvaluate {
publishing {
publications {
register("release",MavenPublication::class){
from(components["release"])
groupId = "com.nom.roughtnav"
artifactId = "core"
version = "${project.version}"
}
//
}
}
}

How to use Android Gradle without multi-project

I would like to create an android build with a single build.gradle file. How to do that?
You need at least two build.gradles, a project-level one and a module-level one. They are not the same. You can omit neither of them.
It actually is possible.
The whole problem when trying to create an Android build with a single build.gradle comes from the fact, that a plugins block of the top-level build.gradle can only use plugins from Gradle plugin portal and cannot address anything from buildscript's classpath.
However, there is a pluginManagement block you can add to settings.gradle, that can be used to modify how plugins are resolved.
A working example:
// settings.gradle.kts
rootProject.name = "android_app"
pluginManagement {
repositories {
gradlePluginPortal()
google()
}
resolutionStrategy {
eachPlugin {
if (requested.id.name.startsWith("com.android")) {
useModule("com.android.tools.build:gradle:${requested.version}")
}
}
}
}
// build.gradle.kts
plugins {
id ("com.android.application") version "4.2.2"
}
group = "pl.gieted.android_app"
version = "1.12-SNAPSHOT"
android {
compileSdkVersion(31)
defaultConfig {
applicationId = group.toString()
minSdkVersion(24)
targetSdkVersion(31)
versionName = version.toString()
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
buildTypes {
getByName("release") {
isMinifyEnabled = false
}
}
}

How can I add docstrings to android maven-publish .aar files in build.gradle.kts?

I have a project with the standard java library and this creates several .jar files, one being a docset and another the source set. Now I have successfully created an android-library using the maven-publish plugin, but when I add the .aar files to another project, they don't contain neither source nor comments as the .jar version did, so I don't get help inside the IDE or look into the implementation of methods.
What do I need to add to my build.gradle.kts to include docstrings and sources in the debug version of the .aar I'm publishing locally as a file? The linked gradle documentation from that Android developer page does not mention anything about docstrings or sources at all.
import org.jetbrains.kotlin.config.KotlinCompilerVersion
plugins {
id("com.android.library")
kotlin("android")
`maven-publish`
}
group = "com.wavelt.libs"
version = "1.0.0"
android {
compileSdkVersion(30)
buildToolsVersion = "30.0.2"
defaultConfig {
minSdkVersion(16)
targetSdkVersion(30)
versionCode = 1
versionName = "1.0.0"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles("consumer-rules.pro")
}
buildTypes {
getByName("release") {
isMinifyEnabled = false
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = "1.8"
freeCompilerArgs = listOf("-Xinline-classes")
}
}
dependencies {
implementation(kotlin("stdlib-jdk7", KotlinCompilerVersion.VERSION))
implementation("androidx.core:core-ktx:1.3.2")
implementation("androidx.appcompat:appcompat:1.2.0")
implementation("com.google.android.material:material:1.3.0")
testImplementation("junit:junit:4.13.2")
androidTestImplementation("androidx.test.ext:junit:1.1.2")
androidTestImplementation("androidx.test.espresso:espresso-core:3.3.0")
androidTestImplementation("com.android.support.test:runner:1.0.2")
androidTestImplementation("com.android.support.test:rules:1.0.2")
}
// https://developer.android.com/studio/build/maven-publish-plugin
afterEvaluate {
publishing {
repositories {
maven {
// https://docs.gradle.org/current/userguide/publishing_maven.html#publishing_maven:repositories
url = uri("$buildDir/repository")
}
}
publications {
create<MavenPublication>("debug") {
// Applies the component for the release build variant.
from(components["debug"])
artifactId = "wavelt-android-debug"
artifact("androidJavadocsJar") // Doesn't seem to work
}
create<MavenPublication>("release") {
// Applies the component for the release build variant.
from(components["release"])
artifactId = "wavelt-android"
}
}
}
}
While I've read about other devs being able to cram the javadocs into the .aar file, this is not explicitly necessary at all to gain documentation and source code inspection from inside IDEs like Android Studio. In fact, looking at the way a typical java library works, it creates files like:
foo-ver.jar
foo-ver-sources.jar
foo-ver-javadoc.jar
The only difference with an Android library would be having these files:
foo-ver.aar
foo-ver-sources.jar
foo-ver-javadoc.jar
Which means that the sources and javadoc jars can still be copied along the .aar and the IDE will load them. Having said that, the publish example code only creates the .aar file, looking at other questions like this one I was able to modify the script to create the .aar plus the two other .jar packages:
import org.jetbrains.kotlin.config.KotlinCompilerVersion
plugins {
id("com.android.library")
kotlin("android")
`maven-publish`
id("org.jetbrains.dokka") version "0.9.17"
}
group = "com.wavelt.libs"
version = "1.0.0"
android {
compileSdkVersion(30)
buildToolsVersion = "30.0.2"
defaultConfig {
minSdkVersion(16)
targetSdkVersion(30)
versionCode = 1
versionName = "1.0.0"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles("consumer-rules.pro")
}
buildTypes {
getByName("release") {
isMinifyEnabled = false
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = "1.8"
freeCompilerArgs = listOf("-Xinline-classes")
}
}
dependencies {
//implementation(fileTree(mapOf("dir" to "libs", "include" to listOf("*.jar"))))
implementation(kotlin("stdlib-jdk7", KotlinCompilerVersion.VERSION))
implementation("androidx.core:core-ktx:1.3.2")
implementation("androidx.appcompat:appcompat:1.2.0")
implementation("com.google.android.material:material:1.3.0")
testImplementation("junit:junit:4.13.2")
androidTestImplementation("androidx.test.ext:junit:1.1.2")
androidTestImplementation("androidx.test.espresso:espresso-core:3.3.0")
androidTestImplementation("com.android.support.test:runner:1.0.2")
androidTestImplementation("com.android.support.test:rules:1.0.2")
}
tasks.dokka {
outputFormat = "html"
outputDirectory = "$buildDir/javadoc"
moduleName = rootProject.name
}
val dokkaJar by tasks.creating(Jar::class) {
group = JavaBasePlugin.DOCUMENTATION_GROUP
description = "Assembles Kotlin docs with Dokka"
archiveClassifier.set("javadoc")
from(tasks.dokka)
dependsOn(tasks.dokka)
}
val sourcesJar by tasks.creating(Jar::class) {
group = JavaBasePlugin.DOCUMENTATION_GROUP
description = "Assembles sources JAR"
archiveClassifier.set("sources")
from(android.sourceSets.getByName("main").java.srcDirs)
}
artifacts {
archives(sourcesJar)
archives(dokkaJar)
}
// https://developer.android.com/studio/build/maven-publish-plugin
afterEvaluate {
publishing {
repositories {
maven {
// https://docs.gradle.org/current/userguide/publishing_maven.html#publishing_maven:repositories
url = uri("$buildDir/repository")
}
}
publications {
create<MavenPublication>("debug") {
// Applies the component for the release build variant.
from(components["debug"])
artifactId = "wavelt-android-debug"
artifact(sourcesJar)
artifact(dokkaJar)
}
create<MavenPublication>("release") {
// Applies the component for the release build variant.
from(components["release"])
artifactId = "wavelt-android"
}
}
}
}
With these modifications the ./gradlew publish task will generate all files, and despite one of them having .aar they work the same as .jar when copied together into another project.

Categories

Resources