본문 바로가기

안드로이드

Android - BuildSrc + Version Catalog ( 안드로이드 버전 관리하기 )

반응형

안드로이드에서 버전을 관리하는 방법이 점점 많아지고 있다.

간단하게 정리하자면,

1. ext를 통한 관리

Gradle에서 라이브러리 업데이트 가능 정보가 노출된다.

2. buildsrc를 통한 관리

플러그인들을 작성하기 쉽다.
라이브러리 업데이트 정보를 알 수 없다. ( 별도의 라이브러리를 쓰면 해결은 된다. )
코드상에서 버전을 하나만 바꿔도 캐시를 무시하고 전체를 다시 빌드한다.

3. version catalog를 통한 관리

버전을 깔끔하게 관리할 수 있고, bundle 형태로 묶어서 관리할 수도 있다.
라이브러리 업데이트 정보를 알 수 없다. ( 별도의 라이브러리나 renovate를 쓸 수 있다. )

 

ext를 벗어날수록 라이브러리 버전에 대한 유지 능력은 점점 떨어지고, 다른 곁가지에만 뭐가 계속 붙고 있다.

 

builSrc에서 버전 관리를 하면 현재로선 어떠한 이점도 없기 때문에
( 숫자만 바꿔도 캐시가 무효화되고, 라이브러리 업데이트 여부도 알 수 없다. )
버전 관리 부분만을 뽑아서 verion catelog로 옮겨보자.

1. Version Catalog

gradle 7.4 버전에서 별도의 설정 없이 사용할 수 있다.

enableFeaturePreview("VERSION_CATALOGS")

이전 버전의 경우 preview 활성화를 통해서 사용할 수 있다.

// gradle/libs.version.toml

[versions]
compose = "1.3.0"
compose_compiler = "1.3.2"
...

[libraries]
...

compose-ui = { module = "androidx.compose.ui:ui", version.ref = "compose" }
compose-material = { module = "androidx.compose.material:material", version.ref = "compose" }
compose-ui-tooling = { module = "androidx.compose.ui:ui-tooling", version.ref = "compose" }
compose-runtime = { module = "androidx.compose.runtime:runtime", version.ref = "compose" }
compose-runtime-livedata = { module = "androidx.compose.runtime:runtime-livedata", version.ref = "compose" }
compose-ui-test = { module = "androidx.compose.ui:ui-test-junit4", version.ref = "compose" }
...

[bundles]
compose = ["compose-ui", "compose-material", "compose-ui-tooling", "compose-runtime", "compose-runtime-livedata"]
...

[plugins]
...

위의 예제가 version Catalog에서 버전을 선언하는 방법이다.

 

gradle/libs.version.toml이라는 파일을 만들고 그 안에 라이브러리 정보를 적어준다.
그룹핑할 수 있는 정보는 versions, libraries, bundles, plugins 정도가 있다.

 

여기서 네이밍에 - 로 포함한 것은 전부 뎁스로 치환된다.

dependencies {

    implementation(project(":core"))
    implementation(project(":domain"))

    testImplementation(libs.junit)

    implementation(libs.hilt.navigation)

    implementation(libs.compose.paging)
    implementation(libs.bundles.compose)
}

version Catalog를 통해서 라이브러리를 선언하면 위에 예제처럼 사용할 수 있다.
bundles의 경우 bundles을 통하여 접근해야 한다.

@Suppress("DSL_SCOPE_VIOLATION") // Because of IDE bug https://youtrack.jetbrains.com/issue/KTIJ-19370
plugins {
    id(libs.plugins.android.application.get().pluginId) // apply false 프로젝트 레벨에서만
    id(libs.plugins.android.library.get().pluginId) // apply false 프로젝트 레벨에서만
    id(libs.plugins.kotlin.android.get().pluginId) // apply false 프로젝트 레벨에서만
    alias(libs.plugins.hilt) // apply false 프로젝트 레벨에서만

}

plugins에서도 접근할 수 있으며, alias 를 이용하여 사용하면 된다.

 

만약,
Error resolving plugin [id: 'com.android.application', version: '7.3.1', apply: false]
와 같은 이런 에러가 발생한다면 id 를 통해서 적용하면 된다.

2. buildSrc에서 Version Catalog 접근

VersionCatalog는 build.gradle에서만 접근할 수 있고, 코드 내에서는 일반적인 방법으로는 접근할 수가 없다.

 

그리고 buildSrc에서는 코드뿐만 아니라 gradle에서도 접근이 불가능하다.
( BuildSrc/gradle의 실행 타이밍으로 인해 ext 방식과 buildSrc에 직접 정의한 변수도 접근을 못한다. )

1. gradle에서의 접근 방법

// buildSrc/settings.gradle.kts

dependencyResolutionManagement {
    versionCatalogs {
        create("libs") {
            from(files("../gradle/libs.versions.toml"))
        }
    }
}

gradle에서 접근 가능하도록 하려면 buildSrc에 새로운 settings.gradle을 생성하고, 기존의 versionCatalog를 가져와 다시 적용해야 한다.


이렇게 하면 gradle에서는 접근이 가능해진다.

2. 코드에서의 접근

// buildSrc/build.gradle.kts

dependencies {
    ...

    implementation(files(libs.javaClass.superclass.protectionDomain.codeSource.location))
}

코드에서 접근을 위해서는 libs.javaClass.superclass.protectionDomain.codeSource.location 라는 파일을 들고 와줘야 한다.


이 파일 안에 versionCatalog에 접근할 수 있는 클래스가 포함되어 있다.

private val Project.libs get() = the<LibrariesForLibs>()

private fun DependencyHandlerScope.implementation(vararg list: Any) {
    list.forEach {
        add("implementation", it)
    }
}

fun Project.applyComposeDependencies() {
    ...
    project.dependencies {
        implementation(libs.bundles.compose)
    }
}

코드 내에서 LibrariesForLibs 클래스를 가져오고 나면, gradle에서 쓴 것과 동일한 방법으로 사용이 가능해진다.

3. buildSrc + VersionCatalog

버전 정보를 VersionCatalog로 빼주었기 때문에 버전이 바뀔 때마다 전체가 빌드돼 된 BuildSrc의 문제도 해결되고, 플러그인은 buildSrc를 통해서 쉽게 커스텀할 수 있다. 현재로서는 buildSrc와 VersionCatalog를 함께 쓰는 조합이 gradle에 이것저것 붙지 않는 최선의 조합인 거 같다. 

그리고 VersionCatalog는 renovate를 지원해주니 버전 관리가 더욱 쉬워진다. ( buildSrc는 그런 거 없다. )

반응형