First time using gradle, any tips?

Just ended to configure all gradle files for a project. It’s is just a sharing if anyone want to point me a way less stupid more sophisticated to make it.

gradle.properties

####################################################################################################
#
# Configurações do Gradle
#
# permite o cache de dados de build do Gradle
org.gradle.caching=true
# desabilita o reporte detalhado do cache de build em debug
org.gradle.caching.debug=false
# permite o armazenamento em cache de dados da configuração do Gradle
org.gradle.configuration-cache=true
# configura apenas projetos relacionados às tarefas em execução
org.gradle.configureondemand
# define como os textos produzidos pelo Gradle serão expostos no console
org.gradle.console=auto
# máximo tempo de espera dos daemons 3h
org.gradle.daemon.idletimeout=10800000
# usa daemon
org.gradle.daemon=true
# reduz o log do daemon
org.gradle.daemon.performance.disable-logging=true
# configura o jvm para os daemons
org.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=1024m -XX:+HeapDumpOnOutOfMemoryError
org.gradle.jvmargs.2=-XX:+UseParallelGC -Dfile.encoding=UTF-8
# permite o paralelismo, pelo Gradle
org.gradle.parallel=true
# complemento para avisos de build
org.gradle.warning.mode=all
####################################################################################################
#
# Configurações da aplicação
#
# migra bibliotecas dependêntes para sua versão AndroidX
# android.enableJetifier=true
# otimização agressiva do Android Gradle Plugin
android.enableR8.fullMode=true
# acelera a compilação quando lida com @OnLifecycleEvent 
android.lifecycleProcessor.incremental=true
# permite o uso das bibliotecas do AndroidX
android.useAndroidX=true
# controla o R8 para não remover código necessário
android.useMinimalKeepRules=true
####################################################################################################
#
# Configurações do projeto (Desacoplamento de Strings)
#
buildlogicName=build-logic
namespaceApp=com.logger.app
namespaceAppTeste=com.loggerTest.app
namespaceList=com.logger.list
namespaceUtilities=com.logger.utilities
palavraLibs=libs
proguardAndroid=proguard-android-optimize.txt
proguardRules=proguard-rules.pro
projectName=Logger
recursosMain=src/main/resources
recursosTest=src/test/resources
subprojectApp=:app
subprojectList=:list
subprojectUtil=:utilities
versionsToml=../gradle/libs.versions.toml
####################################################################################################

libs.versions.toml

[versions] # versão a ser usada de cada biblioteca ou plugin seguida pela fonte de origem
# versões de plugins e biblioteccas
# https://maven.google.com/web/index.html?#com.android.settings:com.android.settings.gradle.plugin
androidGradlePlugin = "8.9.0" # https://mvnrepository.com/artifact/com.android.tools.build/gradle
adrxActivity = "1.10.1" # https://mvnrepository.com/artifact/androidx.activity/activity
adrxAppcompat = "1.7.0" # https://mvnrepository.com/artifact/androidx.appcompat/appcompat
consLt = "2.2.1" # https://mvnrepository.com/artifact/androidx.constraintlayout/constraintlayout
xprssCore = "3.6.1" # https://mvnrepository.com/artifact/androidx.test.espresso/espresso-core
material = "1.12.0" # https://mvnrepository.com/artifact/com.google.android.material/material
testng = "7.11.0" # https://mvnrepository.com/artifact/org.testng/testng

# outras versões
javaSource = "21"
javaTarget = "21"
versaoNome = "1.00.00.000" # string - nome livre (v1.v2.semana.mudança)
versaoNumero = "1" # inteiro - pro google play store
sdkCompile = "35" # https://developer.android.com/guide/topics/manifest/uses-sdk-element
sdkMin = "26" # https://developer.android.com/guide/topics/manifest/uses-sdk-element
sdkTarget = "35" # https://developer.android.com/guide/topics/manifest/uses-sdk-element

[libraries] # declaração dos nomes das bibliotecas
adrxActivity = { group = "androidx.activity", name = "activity", version.ref = "adrxActivity" }
adrxAppcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "adrxAppcompat" }
consLt = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "consLt" }
xprssCore = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "xprssCore" }
material = { group = "com.google.android.material", name = "material", version.ref = "material" }
testng = { group = "org.testng", name = "testng", version.ref = "testng" }

[plugins] # declaração dos plugins
androidApplication = { id = "com.android.application", version.ref = "androidGradlePlugin" }
androidLibrary = { id = "com.android.library", version.ref = "androidGradlePlugin" }
buildLogicAndroidApplication = { id = "build-logic.android-app" }
buildLogicAndroidGeral = { id = "build-logic.android-geral" }
buildLogicAndroidLibrary = { id = "build-logic.android-bib" } // it is just buildLogicAndroidGeral 
groovyGradle = { id = "groovy-gradle-plugin" }

root settings.gradle

// Administração de dependências
pluginManagement {
    includeBuild(buildlogicName) // dependência para lógica de build
    // Aonde buscar para cumprir as dependências
    repositories {
        google() // repositório oficial do google
        mavenCentral() // dependências de java e android
        gradlePluginPortal() // repositório oficial do gradle
    }
}
// Resolução de dependências
dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) // força a declaração no settings
    // Aonde buscar para cumprir as dependências
    repositories {
        google() // repositório oficial do google
        mavenCentral() // dependências de java e android
        gradlePluginPortal() // repositório oficial do gradle
    }
}

rootProject.name = projectName // nome da pasta do projeto - pasta raiz
include(subprojectApp, subprojectList, subprojectUtil) // nome da pasta do código do app

.\app\build.gradle

// Declaração dos plugins da app
plugins {
    alias libs.plugins.androidApplication // plugin oficial para aplicações Android
    alias libs.plugins.buildLogicAndroidApplication // plugin para configurações gerais do app
}
// Definição das características do aplicativo
android {
    namespace = project.properties.namespaceApp // identificador para o pacote do aplicativo
    testNamespace = project.properties.namespaceAppTeste // identificador para testes do aplicativo
}
// Biblioteras para serem usadas no código
dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar']) // inclui jars como dependências
    implementation project(project.properties.subprojectUtil) // projetos sem acesso às dependências
}

.\utilities\build.gradle

// Declaração dos plugins do utilities
plugins {
    alias libs.plugins.androidLibrary // necessario para fazer uma biblioteca Android
    alias libs.plugins.buildLogicAndroidLibrary // plugin para configurações gerais da biblioteca
}
// Definição das características do aplicativo
android {
    namespace = project.properties.namespaceUtilities // identificador para o pacote do aplicativo
}
// Biblioteras para serem usadas no código
dependencies {
    api project(project.properties.subprojectList) // api pega dados e compartilha
}

./build-logic/settings.gradle

// Busca e define o lisb.versions.toml como libs e usa como catálogo de versão
final Properties propriedadesRaiz = new Properties()
rootProject.projectDir.parentFile.listFiles().any { final file ->
    if (file.isFile()) {
        propriedadesRaiz.load(new FileInputStream(file))
        if (propriedadesRaiz.buildlogicName != null) {
            return true
        }
    }
}
// Resolução de dependências
dependencyResolutionManagement {
    // Acesso ao libs.versions.toml
    versionCatalogs {
        create(propriedadesRaiz.palavraLibs) {
            from(files(propriedadesRaiz.versionsToml)) // Direct path
        }
    }
}

rootProject.name = propriedadesRaiz.buildlogicName // nome da pasta do projeto

./build-logic/build.gradle

plugins {
    alias libs.plugins.groovyGradle
}

./build-logic/src/main/groovy/build-logic.android-geral.gradle

// Definição das características do aplicativo
android {
    // Configurações padrão para o aplicativo Android
    defaultConfig {
        compileSdk = libs.versions.sdkCompile.get().toInteger() // compatibilidade APIs do Android
        minSdk = libs.versions.sdkMin.get().toInteger() // versão Android mínima
        targetSdk = libs.versions.sdkTarget.get().toInteger() // versão Android principal
    }
    // Versão java para compilar o código e manter a compatibilidade
    compileOptions {
        sourceCompatibility = JavaVersion.toVersion(libs.versions.javaSource.get())
        targetCompatibility = JavaVersion.toVersion(libs.versions.javaTarget.get())
    }
    // Define o local do código para o android
    sourceSets {
        // Código principal, androidx usa res, mas o gradle cria resources
        main {
            // Recursos do código
            res.srcDirs = [project.properties.recursosMain]
        }
        // Códigos de teste
        test {
            // Recursos dod códigos de teste, androidx usa res, mas o gradle cria resoures
            res.srcDirs = [project.properties.recursosTest]
        }
    }
}
// Biblioteras para serem usadas no código
dependencies {
    implementation(libs.adrxActivity) // base para fazer Activities
    implementation(libs.adrxAppcompat) // compatibilidade com versões antigas
    testImplementation(libs.testng) // framework do TestNG
}
// Aplica tipo de test TestNG
tasks.withType(Test).configureEach {
    useTestNG() // aplica o TestNG
}

./build-logic/src/main/groovy/build-logic.android-app.gradle

// Declaração dos plugins da app
plugins.apply(libs.plugins.buildLogicAndroidGeral.get().getPluginId())
// Definição das características do aplicativo
android {
    // Configurações padrão para o aplicativo Android
    defaultConfig {
        applicationId project.properties.namespaceApp // identificador na Google Play Store
        versionCode libs.versions.versaoNumero.get().toInteger() // versão do para Google Play Store
        versionName libs.versions.versaoNome.get() // nome da versão do código exibido aos usuários
    }
    // Controle sobre compilaação
    buildFeatures{
        buildConfig = false
    }
    // Controle de builds para o aplicativo
    buildTypes {
        // Regras para a release do aplicativo
        release {
            minifyEnabled = false
            proguardFiles getDefaultProguardFile(
                    project.properties.proguardAndroid), project.properties.proguardRules
        }
        // Regras para a debug do aplicativo
        debug {
            minifyEnabled = false // desabilita o encolhimento de código
        }
    }
    // Ativa a view binding para melhorar as views do aplicativo
    viewBinding {
        enable = true
    }
}
// Biblioteras para serem usadas no código
dependencies {
    androidTestImplementation(libs.xprssCore) // framework do Andoird para testes
    androidTestImplementation(libs.testng) // framework do TestNG permitido para android
    implementation(libs.consLt) // layouts complexos
    implementation(libs.material) // experiência visual
}

You should start with posting in the right category, Meta is for questions to the forum itself not Gradle. :smiley:

But besides that, it is unlikely that someone will review your whole build for you. I will surely not for at least two reasons I’m too lazy, and it is Android.

But some points from a very cursory look:

  • use Kotlin DSL instead of Groovy DSL, by now it is the default DSL, you immediately get type-safe build scripts, actually helpful error messages if you mess up the syntax, and amazingly better IDE support if you use a good IDE like IntelliJ IDEA or Android Studio
  • why do you have Gradle Plugin Portal as repository for normal dependencies, that makes little sense unless you develop a Gradle plugin that depends on other 3rd party plugins
  • don’t use fileTree or files for dependencies. Better not use local file dependencies at all. If you really must, at least use a flatDir repository and normal dependency declarations
  • your propriedadesRaiz seems to be very unnecessary and very fragile. For example you never close the file handles you open, and you read any file you find as properties file, no matter what it is. And also settingsDir would probably be more appropriate than rootProject.projectDir.
1 Like

Thank you for taking a look at it.

I didn’t expect anyone to review everything in detail, I was just hoping for a quick overview, like you provided.

I read through all the topic descriptions, but none seemed to fit my request, so I just choose one at randomly.

Regarding fileTree and gradlePluginPortal(), they were already present when I created the Gradle project, so I let them rest there.

I gonna take a look on propriedadesRaiz, my intention was to avoid using literal strings directly in the code.

Also, I’m not currently using an IDE, but I plan to try Kotlin DSL because I’m really missing helpful error messages.

I read through all the topic descriptions, but none seemed to fit my request

But you picked the on that fit the least, the one that is about the actual forum and not at all about Gradle. :smiley:
If in in doubt, “Help/Discuss” is your friend.

Regarding fileTree and gradlePluginPortal() , they were already present when I created the Gradle project, so I let them rest there.

I have no idea how you “created” it.
Gradle would never have added those.
(well the second maybe if you told it to create a Gradle Plugin project)
I guess you used some generator or tutorial or blueprint or whatever and should report to that, that they are generating non-sense.
:man_shrugging:

my intention was to avoid using literal strings directly in the code.

The question is: Why?
For many things that might be good, but you seem to have greatly overdone it.
I mean, ok, if you want to define the name of the build logic project in the properties file, fine, I wouldn’t do that, but that is just personal preference maybe.
But detecting the properties file (even when ignoring the faulty and flaky implementation) does really not make much sense.
Additionally you will do this on each and every build invocation.
Besides that it could probably make problems if you ever hope to use configuration cache which I can highly recommend.
If you have one codebase in one VCS that is a unit and you want to refer a file from another place of that, by all means, use an explicit String please and not some wonky and totally unnecessary file detection.

I mean, sure, it is your project, do what you like.
If that is what you want to use, do it, but you asked for opinion. :slight_smile:
After fixing the problems with the detection you could of course leave it in.
It just makes the build very much less maintainable and understandable, and of course slower. :slight_smile:
If I were you, I would just hard-code the path to the version catalog file and the build logic name, or at least the path to the properties file. :man_shrugging:

Gonna take it in mind.

gradlePluginPortal()shows up in build-logic:build.gradle when using the init command:

gradle init --type java-application --java-version 21 --project-name Nome --dsl groovy --split-project --incubating --no-comments

I should have messed up and copied it to root settings before deleting from build-logic.
I have absolute no idea where fileTreecame from. Must have take it from some project I was taking inspirating on GitHub. I have never use it, and most of my commits have it commented or missing.

Good practice :slight_smile:
I know overdone it. But when I opened it on Android Studio, the warning about literal strings convinced me about do it. Smae with apply.plugin() in build-logic. I gonna review it later anyway.

gradlePluginPortal() shows up in build-logic:build.gradle when using the init command:

Of course, that build is for building convention plugins, so there the probability is high that you actually want to depend on 3rd-party plugins from the Gradle Plugin Portal. :slight_smile:

But when I opened it on Android Studio, the warning about literal strings convinced me about do it.

It warns you about literal strings in build scripts?
That sounds quite unlikely, as there is barely one build script that is written without literal strings, and doing so is the idiomatic and good-practice way.
Maybe you changed some configuration to get that or installed some plugin that does this? :man_shrugging:

Whatever is causing such a result is not a good advice, but a bug. :slight_smile:
Yes, in normal code it is usually better to avoid literal strings or magic numbers, especially if they are something that is shown to a user and might need translations at some point.
But in Gradle build scripts this is really a bad advice imho. :slight_smile:

Indeed. I’m not sure why did I take it off and insert in root setting.gradle.

It does, I’m almost sure it comes by default.

Thanks for advice me.