This directory contains Gradle convention plugins that centralize build configuration across the Grapla project. The structure is inspired by dashiki and follows best practices for organizing build logic.
Instead of repeating the same Gradle configuration in every module, you define it once in a plugin and apply it where needed. This keeps your build scripts DRY (Don't Repeat Yourself) and makes configuration changes easier to manage.
grapla.android.application- Android app configurationgrapla.android.application.compose- Compose support for appsgrapla.android.application.firebase- Firebase integration
grapla.android.library- Android library configurationgrapla.android.library.compose- Compose support for librariesgrapla.android.feature- Feature module setup
grapla.hilt- Dependency injection (Hilt/Dagger)grapla.android.room- Room database setupgrapla.android.lint- Linting configuration
grapla.android.test- Android test modulesgrapla.android.unit.test- Unit test configuration (JUnit 6, Robolectric)grapla.android.instrumented.test- Instrumented test setup (Espresso, UI Automator)grapla.android.compose.test- Compose UI test configuration
grapla.kover- Kover coverage (Kotlin-first)grapla.jacoco- JaCoCo coverage (Java/Kotlin)
grapla.detekt- Static code analysis (Detekt)
grapla.android.flavor- Product flavor setup (environment, version dimensions)
grapla.jvm.library- Pure Kotlin/JVM libraries
buildLogic/
├── settings.gradle.kts # Build logic settings
├── gradle.properties # Build logic properties
├── README.md # This file
└── convention/
├── build.gradle.kts # Plugin registration
└── src/main/kotlin/
├── application/ # App-level plugins
│ ├── AndroidApplicationConventionPlugin.kt
│ ├── AndroidApplicationComposeConventionPlugin.kt
│ └── AndroidApplicationFirebaseConventionPlugin.kt
├── library/ # Library-level plugins
│ ├── AndroidLibraryConventionPlugin.kt
│ └── AndroidLibraryComposeConventionPlugin.kt
├── feature/ # Feature module plugins
│ └── AndroidFeatureConventionPlugin.kt
├── hilt/ # Dependency injection
│ └── HiltConventionPlugin.kt
├── android/ # Android-specific plugins
│ ├── AndroidRoomConventionPlugin.kt
│ └── AndroidLintConventionPlugin.kt
├── test/ # Testing plugins
│ └── AndroidTestConventionPlugin.kt
├── jvm/ # JVM plugins
│ └── JvmLibraryConventionPlugin.kt
└── util/ # Shared utilities
├── BuildLogicConstants.kt
├── ProjectExtensions.kt
├── DependencyConfig.kt
├── KotlinAndroid.kt
├── AndroidCompose.kt
└── AndroidInstrumentedTests.kt
- Single Responsibility - Each plugin has one clear purpose
- Composability - Plugins can be combined (e.g., library + compose + hilt)
- Consistency - All modules of the same type have identical configuration
- Maintainability - Change once, apply everywhere
- Type Safety - Use the version catalog with type-safe accessors
// app/build.gradle.kts
plugins {
id("grapla.android.application")
id("grapla.android.application.compose")
id("grapla.hilt")
id("grapla.android.flavor")
id("grapla.kover")
id("grapla.detekt")
}
dependencies {
// Your app dependencies
}// core/ui/build.gradle.kts
plugins {
id("grapla.android.library")
id("grapla.android.library.compose")
id("grapla.android.unit.test")
id("grapla.android.compose.test")
}
dependencies {
// Your library dependencies
}// feature/home/build.gradle.kts
plugins {
id("grapla.android.feature")
id("grapla.android.library.compose")
id("grapla.android.unit.test")
id("grapla.android.instrumented.test")
id("grapla.android.compose.test")
id("grapla.jacoco")
}
dependencies {
// Feature-specific dependencies
// Common feature dependencies are already included by the feature plugin
}// core/data/build.gradle.kts
plugins {
id("grapla.android.library")
id("grapla.android.room")
id("grapla.hilt")
id("grapla.android.unit.test")
id("grapla.kover")
id("grapla.detekt")
}
dependencies {
// Your data layer dependencies
}All SDK versions and other constants are centralized in util/BuildLogicConstants.kt:
object BuildLogicConstants {
const val COMPILE_SDK = 36
const val TARGET_SDK = 36
const val MIN_SDK = 28
const val JAVA_VERSION = "21"
const val KOTLIN_JVM_TARGET = "21"
}Plugins can access the version catalog using the libs extension:
dependencies {
add("implementation", libs.findLibrary("androidx.core.ktx").get())
}- Create a new Kotlin file in the appropriate package (e.g.,
quality/DetektConventionPlugin.kt) - Implement the
Plugin<Project>interface - Register the plugin in
convention/build.gradle.kts:
register("detekt") {
id = "grapla.detekt"
implementationClass = "quality.DetektConventionPlugin"
}- Use it in your modules:
plugins {
id("grapla.detekt")
}