이제 마지막으로 Convention 모듈을 만들어 커스텀 플러그인 설정을 하는 방법을 설명 하겠습니다.
예를 들어 모듈별로 필요한 플러그인 들을 여러개 추가 할 때 마다 build.gradle에 중복 코드가 많아지는데 커스텀 플러그인 을 통해서 효과적으로 관리를 할 수 있게 됩니다.
1. build-logic 모듈을 생성하고 settings.gradle.kts 만 남겨 놓습니다.
2. build-logic 모듈 안에 convention 모듈을 생성 합니다.
3. root 디렉토리의 setting.gradle 에서 build-logic , convention 모듈을 지웁니다.
pluginManagement {
includeBuild("build-logic") // 필수
repositories {
google()
mavenCentral()
gradlePluginPortal()
}
}
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
}
}
rootProject.name = "LedBillboard"
include ':app'
4. build-logic 의 settings.gradle 에 versionCatalog 에 대해 명시합니다.
dependencyResolutionManagement {
repositories {
google()
mavenCentral()
gradlePluginPortal()
}
versionCatalogs {
create("libs") {
from(files("../gradle/libs.versions.toml"))
}
}
}
rootProject.name = "build-logic"
include(":convention")
5. convention module 안의 패키지에서 Android Kotlin 과 Compose 세팅을 도와주는 확장 함수를 만들어 줍니다.
- Android kotlin 관련
internal fun Project.configureKotlinAndroid(
commonExtension: CommonExtension<*, *, *, *>,
) {
commonExtension.apply {
compileSdk = 34
defaultConfig {
minSdk = 24
testInstrumentationRunner = "android.support.test.runner.AndroidJUnitRunner"
vectorDrawables.useSupportLibrary = true
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
kotlinOptions {
jvmTarget = JavaVersion.VERSION_11.toString()
}
}
}
fun CommonExtension<*, *, *, *>.kotlinOptions(block: KotlinJvmOptions.() -> Unit) {
(this as ExtensionAware).extensions.configure("kotlinOptions", block)
}
- Android compose 관련
internal fun Project.configureAndroidCompose(
commonExtension: CommonExtension<*, *, *, *>,
) {
val libs = extensions.getByType<VersionCatalogsExtension>().named("libs")
commonExtension.apply {
buildFeatures.compose = true
composeOptions {
kotlinCompilerExtensionVersion = libs.findVersion("composeCompiler").get().toString()
}
}
dependencies {
// Disabling to work with Alpha
// "api"(platform(libs.findLibrary("compose.bom").get()))
"implementation"(libs.findBundle("androidX-compose").get())
"debugImplementation"(libs.findBundle("androidX-compose-debug").get())
}
}
6. Plugin 클래스를 생성하여 위에서 정의한 확장함수를 이용하여 커스텀 plugin 을 만듭니다.
- AndroidApplicationConventionPlugin
import com.android.build.api.dsl.ApplicationExtension
import com.example.ledbillboard.configureKotlinAndroid
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.kotlin.dsl.configure
internal class AndroidApplicationConventionPlugin : Plugin<Project> {
override fun apply(target: Project) {
with(target) {
with(pluginManager) {
apply("com.android.application")
apply("org.jetbrains.kotlin.android")
}
extensions.configure<ApplicationExtension> {
configureKotlinAndroid(this)
buildTypes {
release {
isMinifyEnabled = false
proguardFiles ("proguard-rules.pro")
}
}
packagingOptions {
resources {
excludes.add("/META-INF/{AL2.0,LGPL2.1}")
}
}
}
}
}
}
- AndroidApplicationComposeConventionPlugin
import com.android.build.gradle.internal.dsl.BaseAppModuleExtension
import com.example.ledbillboard.configureAndroidCompose
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.kotlin.dsl.getByType
class AndroidApplicationComposeConventionPlugin : Plugin<Project> {
override fun apply(target: Project) {
with(target) {
pluginManager.apply("com.android.application")
val extension = extensions.getByType<BaseAppModuleExtension>()
configureAndroidCompose(extension)
}
}
}
7. convention 모듈의 build.gradle.kts 에 gradlePlugin 을 세팅 해줍니다.
plugins {
`kotlin-dsl`
}
group = "com.example.ledbillboard.buildlogic"
java {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
dependencies {
compileOnly(libs.android.gradlePlugin)
compileOnly(libs.kotlin.gradlePlugin)
// compileOnly(libs.ksp.gradlePlugin)
}
gradlePlugin {
plugins {
register("AndroidApplicationPlugin") {
id = "hyosik.plugin.application"
implementationClass = "AndroidApplicationConventionPlugin"
}
register("AndroidApplicationComposePlugin") {
id = "hyosik.plugin.application.compose"
implementationClass = "AndroidApplicationComposeConventionPlugin"
}
}
}
8. 마지막으로 gradlePlugin 에 있는 register id 값을 다른 모듈에서 plugin 으로 추가를 하면 됩니다.
plugins {
id("hyosik.plugin.application")
id("hyosik.plugin.application.compose")
}
apply {
from(rootProject.file("android.gradle"))
}
dependencies {
implementation (libs.androidX.core.ktx)
implementation (libs.androidX.lifecycle.runtimeTesting)
implementation (libs.androidX.activity.compose)
testImplementation (libs.junit)
androidTestImplementation (libs.androidX.test.junit)
androidTestImplementation (libs.androidX.test.espresso)
androidTestImplementation (libs.androidX.compose.uiTestJunit)
debugImplementation (libs.androidX.compose.tooling)
debugImplementation (libs.androidX.compose.uiTestManifest)
}
build- logic 및 convention 모듈의 구조는 이렇게 나옵니다.
현재 저는 Application Plugin 과 Library Plugin 두가지를 만든 상황이고 앞으로 hilt 관련 Plugin 도 만들 생각입니다.
그럼 여기까지 Version Catalog 및 Convention Plugin 을 도입했던 경험이었습니다.
'안드로이드' 카테고리의 다른 글
Version Catalog 도입기 (2) (0) | 2024.03.28 |
---|---|
Version Catalog 도입기 (1) (0) | 2024.03.28 |
[android/hilt] @Binds vs @Provides (0) | 2024.03.18 |
[android/안드로이드] Cold Stream , Hot Stream 차이점 (0) | 2022.06.08 |
[android/안드로이드] AAC ViewModel VS MVVM ViewModel (0) | 2022.05.03 |