익숙하지 않은 Groovy언어로 BuildScript를 작성하는 것에 한계를 느껴 언젠가는 Kotlin DSL로 Migration해야 겠다고 생각했는데, 이번에 시간이 생겨 Migration을 진행하였다.
Migration을 진행하면서 달라진 문법 구조로 인해 대형 프로젝트에서는 Migration을 진행하기 조금 어려울 수도 있겠다는 생각이 들어 정리를 할 필요성을 느끼게 되어 정리를 하게 되었다.
프로젝트 예제: https://github.com/seyoungcho2/GradleKotlinDSL
Migration
프로젝트 시작
이번 Migration은 Android에서 제공해주는 기본 프로젝트 중 Empty Activity를 바탕으로 진행하며 환경은 Kotlin 1.5이다.
setting.gradle을 setting.gradle.kts로 변경
setting.gradle은 gradle 프로젝트를 세팅 하기 위한 정보를 포함한다. 이 gradle 파일을 setting.gradle.kts로 변경하여야 한다.
그림4와 같이 Rename 버튼을 눌러 변경하도록 하자
Groovy에서 Kotlin 파일로 변경되었으므로 내부 코드도 변경해야 한다.
1. 변경전
rootProject.name = "GradleKotlinDSL"
include ':app'
2. 변경 후
rootProject.name = "GradleKotlinDSL"
include(":app")
Kotlin에서는 '을 쓰지 않고 "로 String 값을 나타내브로 '는 모두 "로 변경한다.
프로젝트 수준의 build.gradle 파일 변경
이제 Project 수준의 build.gradle 파일을 변경한다. build.gradle.kts로 변경한다.
이름을 변경했으면 내부를 변경한다.
원 코드는 다음과 같다.
buildscript {
ext.kotlin_version = "1.5.0"
repositories {
google()
mavenCentral()
}
dependencies {
classpath "com.android.tools.build:gradle:4.2.1"
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
allprojects {
repositories {
google()
mavenCentral()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
이를 다음과 같이 변경한다. Version과 관련된 세팅은 다음 글에서 다룰 것이므로 여기서는 1.5.0 버전으로 fix시킨다.
buildscript {
repositories {
google()
mavenCentral()
}
dependencies {
classpath("com.android.tools.build:gradle:4.2.1")
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.5.0")
}
}
allprojects {
repositories {
google()
mavenCentral()
}
}
task("clean", Delete::class) {
delete = setOf(rootProject.buildDir)
}
변경된 부분이 많다. dependencies 내부의 classpath는 함수의 인자로 classpath 값을 받고 task는 이름과 작업 class를 setting 해준다.
fun <T : Task> Project.task(name: String, type: KClass<T>, configuration: T.() -> Unit) =
tasks.create(name, type.java, configuration)
모듈 수준의 build.gradle 변경
모듈 수준의 build.gradle을 변경해보자. 마찬가지로 build.gradle을 build.gradle.kts로 변경한다.
모듈 수준의 build.gradle 파일에는 '가 많다. 이를 모두 "로 변경해주어야한다.
plugins {
id 'com.android.application'
id 'kotlin-android'
}
android {
compileSdkVersion 30
defaultConfig {
applicationId "com.teamcarelab.gradlekotlindsl"
minSdkVersion 23
targetSdkVersion 30
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled 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 "org.jetbrains.kotlin:kotlin-stdlib:1.5.0"
implementation 'androidx.core:core-ktx:1.5.0'
implementation 'androidx.appcompat:appcompat:1.3.0'
implementation 'com.google.android.material:material:1.3.0'
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
testImplementation 'junit:junit:4.+'
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
}
먼저 plugin부터 보자 plugin은 다음과 같이 id값의 변수로 plugin명을 받도록 변경한다.
plugins {
id("com.android.application")
id("kotlin-android")
}
android 블록은 어떤건 함수로 짜여있고 어떤건 내부 프로퍼티로 짜여있다. 잘 보고 하나하나 설정 해주어야 한다. 왜 이렇게 해두었는지는 잘 모르겠지만, 통일성이 조금 없어 보인다. 이해가 안간다면 모든 코드가 완성되면 android studio에서 내부 참조에 대한 접근이 가능해지니 살펴보도록 하자.
여기서 조금 특이한 점은 buildType을 getByName이란 것으로 가져오다는 점과 다른 변수명은 안바뀌었는데 minifyEnabled가 isMinifyEnabled로 바뀌었다는 점이다.
android {
compileSdkVersion(30)
defaultConfig {
applicationId = "com.teamcarelab.gradlekotlindsl"
minSdkVersion(23)
targetSdkVersion(30)
versionCode = 1
versionName = "1.0"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
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"
}
}
마지막 dependencies 블록은 통일성 있다. 모든 값들이 함수로 설정되어 있으며 자신이 참조하는 라이브러리명을 변수로 받는다. 따라서 모두 다음과 같이 바꾸면 된다.
dependencies {
implementation("org.jetbrains.kotlin:kotlin-stdlib:1.5.0")
implementation("androidx.core:core-ktx:1.5.0")
implementation("androidx.appcompat:appcompat:1.3.0")
implementation("com.google.android.material:material:1.3.0")
implementation("androidx.constraintlayout:constraintlayout:2.0.4")
testImplementation("junit:junit:4.+")
androidTestImplementation("androidx.test.ext:junit:1.1.2")
androidTestImplementation("androidx.test.espresso:espresso-core:3.3.0")
}
완성된 모듈 수준의 build.gradle은 다음과 같다.
plugins {
id("com.android.application")
id("kotlin-android")
}
android {
compileSdkVersion(30)
defaultConfig {
applicationId = "com.teamcarelab.gradlekotlindsl"
minSdkVersion(23)
targetSdkVersion(30)
versionCode = 1
versionName = "1.0"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
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"
}
}
dependencies {
implementation("org.jetbrains.kotlin:kotlin-stdlib:1.5.0")
implementation("androidx.core:core-ktx:1.5.0")
implementation("androidx.appcompat:appcompat:1.3.0")
implementation("com.google.android.material:material:1.3.0")
implementation("androidx.constraintlayout:constraintlayout:2.0.4")
testImplementation("junit:junit:4.+")
androidTestImplementation("androidx.test.ext:junit:1.1.2")
androidTestImplementation("androidx.test.espresso:espresso-core:3.3.0")
}
이제 sync를 한 후 실행 시켜보도록 하자.