Kotlin 2.1.20의 새로운 기능(What's new in Kotlin 2.1.20)
Kotlin 2.1.20의 새로운 기능(What's new in Kotlin 2.1.20)
Kotlin 2.1.20 릴리스가 나왔어요! 주요 변경점들을 정리하면 다음과 같아요.
본문
출시일: 2025년 3월 20일
Kotlin 2.1.20 릴리스가 나왔어요! 주요 변경점들은 다음과 같아요.
- K2 컴파일러 업데이트: 새 kapt 및 Lombok 플러그인 업데이트
- Kotlin Multiplatform: Gradle의 Application 플러그인을 대체하는 새 DSL
- Kotlin/Native: Xcode 16.3 지원과 새 인라인 최적화
- Kotlin/Wasm: 기본 custom formatters, DWARF 지원, Provider API로의 마이그레이션
- Gradle 지원: Gradle의 Isolated Projects 및 custom publication variants와의 호환성
- 표준 라이브러리: 공통 원자(atomic) 타입, UUID 지원 개선, 새 시간 추적 기능
- Compose 컴파일러:
@Composable함수에 대한 제한 완화 및 기타 업데이트 - 문서화: Kotlin 문서의 중요한 개선
Kotlin 릴리스 주기에 대한 자세한 내용은 Kotlin 릴리스 프로세스를 참고하세요.
IDE 지원
2.1.20을 지원하는 Kotlin 플러그인은 최신 IntelliJ IDEA와 Android Studio에 번들로 포함돼 있어요. IDE에서 Kotlin 플러그인을 업데이트할 필요는 없어요. 빌드 스크립트에서 Kotlin 버전을 2.1.20으로 변경하기만 하면 돼요.
자세한 내용은 새 릴리스로 업데이트를 참고하세요.
OSGi 지원 프로젝트에서 Kotlin 아티팩트의 소스 다운로드
kotlin-osgi-bundle 라이브러리의 모든 의존성 소스가 이제 배포판에 포함돼요. 이를 통해 IntelliJ IDEA가 이러한 소스를 다운로드하여 Kotlin 기호에 대한 문서를 제공하고 디버깅 경험을 개선할 수 있어요.
Kotlin K2 컴파일러
새 Kotlin K2 컴파일러에 대한 플러그인 지원을 계속 개선하고 있어요. 이 릴리스는 새 kapt 및 Lombok 플러그인에 대한 업데이트를 가져와요.
새 기본 kapt 플러그인
Kotlin 2.1.20부터 kapt 컴파일러 플러그인의 K2 구현이 모든 프로젝트에서 기본으로 활성화돼요.
JetBrains 팀은 Kotlin 1.9.20에서 K2 컴파일러와 함께 kapt 플러그인의 새 구현을 시작했어요. 그 이후로 K2 kapt의 내부 구현을 더 개발하고 그 동작을 K1 버전과 유사하게 만들면서 성능도 크게 개선했어요.
K2 컴파일러로 kapt를 사용할 때 문제가 발생하면 이전 플러그인 구현으로 일시적으로 되돌릴 수 있어요.
그러려면 프로젝트의 gradle.properties 파일에 다음 옵션을 추가하세요.
kapt.use.k2=false
문제가 있으면 이슈 트래커에 보고해 주세요.
Lombok 컴파일러 플러그인: @SuperBuilder 지원 및 @Builder 업데이트
Kotlin Lombok 컴파일러 플러그인이 이제 @SuperBuilder 어노테이션을 지원하여 클래스 계층을 위한 빌더를 더 쉽게 만들 수 있어요. 이전에는 Kotlin에서 Lombok을 사용하는 개발자가 상속으로 작업할 때 빌더를 수동으로 정의해야 했어요. @SuperBuilder를 사용하면 빌더가 상위 클래스 필드를 자동으로 상속하여 객체를 생성할 때 이를 초기화할 수 있어요.
또한 이 업데이트에는 몇 가지 개선과 버그 수정이 포함돼요.
@Builder어노테이션이 이제 생성자에서 작동하여 더 유연한 객체 생성을 허용해요. 자세한 내용은 해당 YouTrack 이슈를 참고하세요.- Kotlin에서 Lombok의 코드 생성과 관련된 여러 문제가 해결되어 전반적인 호환성이 개선됐어요. 자세한 내용은 GitHub 변경 로그를 참고하세요.
@SuperBuilder 어노테이션에 대한 자세한 내용은 공식 Lombok 문서를 참고하세요.
Kotlin Multiplatform: Gradle의 Application 플러그인을 대체하는 새 DSL
Gradle 8.7부터 Application 플러그인은 Kotlin Multiplatform Gradle 플러그인과 더 이상 호환되지 않아요. Kotlin 2.1.20은 유사한 기능을 달성하기 위한 실험적 DSL을 도입해요. 새 executable {} 블록은 JVM 타깃의 실행 태스크와 Gradle distributions을 구성해요.
빌드 스크립트의 executable {} 블록 앞에 다음 @OptIn 어노테이션을 추가하세요.
@OptIn(ExperimentalKotlinGradlePluginApi::class)
예를 들어:
kotlin {
jvm {
@OptIn(ExperimentalKotlinGradlePluginApi::class)
binaries {
// Configures a JavaExec task named "runJvm" and a Gradle distribution for the "main" compilation in this target
executable {
mainClass.set("foo.MainKt")
}
// Configures a JavaExec task named "runJvmAnother" and a Gradle distribution for the "main" compilation
executable(KotlinCompilation.MAIN_COMPILATION_NAME, "another") {
// Set a different class
mainClass.set("foo.MainAnotherKt")
}
// Configures a JavaExec task named "runJvmTest" and a Gradle distribution for the "test" compilation
executable(KotlinCompilation.TEST_COMPILATION_NAME) {
mainClass.set("foo.MainTestKt")
}
// Configures a JavaExec task named "runJvmTestAnother" and a Gradle distribution for the "test" compilation
executable(KotlinCompilation.TEST_COMPILATION_NAME, "another") {
mainClass.set("foo.MainAnotherTestKt")
}
}
}
}
이 예시에서 Gradle의 Distribution 플러그인은 첫 번째 executable {} 블록에 적용돼요.
문제가 발생하면 이슈 트래커에 보고하거나 공개 Slack 채널에서 알려주세요.
Kotlin/Native
Xcode 16.3 지원
Kotlin 2.1.21부터 Kotlin/Native 컴파일러는 Xcode의 최신 안정 버전인 Xcode 16.3을 지원해요. Xcode를 업데이트하고 Apple 운영체제용 Kotlin 프로젝트 작업을 계속해도 좋아요.
2.1.21 릴리스는 또한 Kotlin Multiplatform 프로젝트에서 컴파일 실패를 일으킨 관련 cinterop 이슈를 수정해요.
새 인라인 최적화
Kotlin 2.1.20은 실제 코드 생성 단계보다 먼저 수행되는 새 인라인 최적화 패스를 도입해요.
Kotlin/Native 컴파일러의 새 인라인 패스는 표준 LLVM 인라이너보다 더 잘 수행되어 생성된 코드의 런타임 성능을 개선해야 해요.
새 인라인 패스는 현재 실험적(Experimental)이에요. 사용해 보려면 다음 컴파일러 옵션을 사용하세요.
-Xbinary=preCodegenInlineThreshold=40
실험 결과 임계값을 40 토큰(컴파일러가 파싱한 코드 단위)으로 설정하는 것이 컴파일 최적화에 합리적인 절충안이라고 보여줘요. 벤치마크에 따르면 이는 전체적인 성능이 9.5% 개선되는 결과를 줘요. 물론 다른 값도 시험해 볼 수 있어요.
바이너리 크기나 컴파일 시간이 증가하는 것을 경험하면 YouTrack을 통해 보고해 주세요.
Kotlin/Wasm
이 릴리스는 Kotlin/Wasm 디버깅과 프로퍼티 사용을 개선해요. Custom formatters는 이제 개발 빌드에서 바로 작동하고, DWARF 디버깅은 코드 검사를 용이하게 해줘요. 또한 Provider API는 Kotlin/Wasm과 Kotlin/JS의 프로퍼티 사용을 단순화해요.
기본으로 활성화된 Custom formatters
이전에는 Kotlin/Wasm 코드로 작업할 때 웹 브라우저에서 디버깅을 개선하기 위해 custom formatters를 수동으로 구성해야 했어요.
이 릴리스에서 custom formatters는 개발 빌드에서 기본으로 활성화되어 추가 Gradle 구성이 필요 없어요.
이 기능을 사용하려면 브라우저의 개발자 도구에서 custom formatters가 활성화되어 있는지만 확인하면 돼요.
- Chrome DevTools에서는 Settings | Preferences | Console에서 custom formatters 체크박스를 찾으세요.
- Firefox DevTools에서는 Settings | Advanced settings에서 custom formatters 체크박스를 찾으세요.
이 변경은 주로 Kotlin/Wasm 개발 빌드에 영향을 줘요. production 빌드에 특정 요구 사항이 있다면 그에 따라 Gradle 구성을 조정해야 해요. 그러려면 wasmJs {} 블록에 다음 컴파일러 옵션을 추가하세요.
// build.gradle.kts
kotlin {
wasmJs {
// ...
compilerOptions {
freeCompilerArgs.add("-Xwasm-debugger-custom-formatters")
}
}
}
Kotlin/Wasm 코드 디버깅을 위한 DWARF 지원
Kotlin 2.1.20은 Kotlin/Wasm에서 DWARF(arbitrary record format을 사용한 디버깅) 지원을 도입해요.
이 변경으로 Kotlin/Wasm 컴파일러는 생성된 WebAssembly(Wasm) 바이너리에 DWARF 데이터를 포함할 수 있게 돼요. 많은 디버거와 가상 머신이 이 데이터를 읽어 컴파일된 코드에 대한 통찰을 제공할 수 있어요.
DWARF는 주로 독립형 Wasm 가상 머신(VM) 안에서 Kotlin/Wasm 애플리케이션을 디버깅하는 데 유용해요. 이 기능을 사용하려면 Wasm VM과 디버거가 DWARF를 지원해야 해요.
DWARF 지원을 사용하면 Kotlin/Wasm 애플리케이션을 단계별로 실행하고, 변수를 검사하고, 코드 통찰을 얻을 수 있어요. 이 기능을 활성화하려면 다음 컴파일러 옵션을 사용하세요.
-Xwasm-generate-dwarf
Kotlin/Wasm 및 Kotlin/JS 프로퍼티의 Provider API로의 마이그레이션
이전에는 Kotlin/Wasm과 Kotlin/JS 확장의 프로퍼티가 변경 가능(var)했고 빌드 스크립트에서 직접 할당됐어요.
the<NodeJsExtension>().version = "2.0.0"
이제 프로퍼티가 Provider API를 통해 노출되며, 값을 할당하려면 .set() 함수를 사용해야 해요.
the<NodeJsEnvSpec>().version.set("2.0.0")
Provider API는 값이 지연(lazily) 계산되고 태스크 의존성과 제대로 통합되도록 보장하여 빌드 성능을 개선해요.
이 변경으로 직접 프로퍼티 할당은 NodeJsEnvSpec 및 YarnRootEnvSpec 같은 *EnvSpec 클래스를 위해 사용 중단됐어요.
또한 혼동을 피하기 위해 여러 별칭 태스크가 제거됐어요.
| 사용 중단된 태스크 | 대체 |
|---|---|
wasmJsRun |
wasmJsBrowserDevelopmentRun |
wasmJsBrowserRun |
wasmJsBrowserDevelopmentRun |
wasmJsNodeRun |
wasmJsNodeDevelopmentRun |
wasmJsBrowserWebpack |
wasmJsBrowserProductionWebpack 또는 wasmJsBrowserDistribution |
jsRun |
jsBrowserDevelopmentRun |
jsBrowserRun |
jsBrowserDevelopmentRun |
jsNodeRun |
jsNodeDevelopmentRun |
jsBrowserWebpack |
jsBrowserProductionWebpack 또는 jsBrowserDistribution |
빌드 스크립트에서 Kotlin/JS나 Kotlin/Wasm만 사용한다면 Gradle이 할당을 자동으로 처리하므로 조치가 필요 없어요.
하지만 Kotlin Gradle 플러그인을 기반으로 하는 플러그인을 유지 관리하고 플러그인이 kotlin-dsl을 적용하지 않는다면, 프로퍼티 할당을 .set() 함수를 사용하도록 업데이트해야 해요.
Gradle
Kotlin 2.1.20은 Gradle 7.6.3부터 8.11까지 완전히 호환돼요. 최신 Gradle 릴리스까지 사용할 수도 있어요. 하지만 그렇게 하면 사용 중단 경고가 발생할 수 있고 일부 새 Gradle 기능이 동작하지 않을 수 있다는 점을 유의하세요.
이 버전의 Kotlin은 Gradle의 Isolated Projects와의 Kotlin Gradle 플러그인 호환성과 custom Gradle publication variants 지원을 포함해요.
Gradle의 Isolated Projects와 호환되는 Kotlin Gradle 플러그인
이 기능은 현재 Gradle에서 pre-Alpha 상태예요. JS와 Wasm 타깃은 현재 지원되지 않아요. Gradle 8.10 이상 버전에서만, 그리고 평가 목적으로만 사용하세요.
Kotlin 2.1.0부터 프로젝트에서 Gradle의 Isolated Projects 기능을 미리 볼 수 있었어요.
이전에는 시험해 보기 전에 프로젝트를 Isolated Projects 기능과 호환되도록 Kotlin Gradle 플러그인을 구성해야 했어요. Kotlin 2.1.20에서 이 추가 단계는 더 이상 필요하지 않아요.
이제 Isolated Projects 기능을 활성화하려면 시스템 속성을 설정하기만 하면 돼요.
Gradle의 Isolated Projects 기능은 multiplatform 프로젝트와 JVM 또는 Android 타깃만 포함하는 프로젝트 모두에서 Kotlin Gradle 플러그인으로 지원돼요.
특히 multiplatform 프로젝트의 경우 업그레이드 후 Gradle 빌드에 문제가 있다면 다음을 추가해 새 Kotlin Gradle 플러그인 동작을 옵트아웃할 수 있어요.
kotlin.kmp.isolated-projects.support=disable
하지만 multiplatform 프로젝트에서 이 Gradle 속성을 사용하면 Isolated Projects 기능을 사용할 수 없어요.
YouTrack에서 이 기능에 대한 경험을 알려주세요.
custom Gradle publication variants 추가 지원
Kotlin 2.1.20은 custom Gradle publication variants 추가 지원을 도입해요. 이 기능은 multiplatform 프로젝트와 JVM을 타깃으로 하는 프로젝트에서 사용할 수 있어요.
기존 Gradle 변형을 이 기능으로 수정할 수는 없어요.
이 기능은 실험적(Experimental)이에요. 옵트인하려면 @OptIn(ExperimentalKotlinGradlePluginApi::class) 어노테이션을 사용하세요.
custom Gradle publication variant를 추가하려면 Kotlin DSL에서 구성할 수 있는 AdhocComponentWithVariants 인스턴스를 반환하는 adhocSoftwareComponent() 함수를 호출하세요.
plugins {
// Only JVM and Multiplatform are supported
kotlin("jvm")
// or
kotlin("multiplatform")
}
kotlin {
@OptIn(ExperimentalKotlinGradlePluginApi::class)
publishing {
// Returns an instance of AdhocSoftwareComponent
adhocSoftwareComponent()
// Alternatively, you can configure AdhocSoftwareComponent in the DSL block as follows
adhocSoftwareComponent {
// Add your custom variants here using the AdhocSoftwareComponent API
}
}
}
변형에 대한 자세한 내용은 Gradle의 Customizing publishing 가이드를 참고하세요.
표준 라이브러리
이 릴리스는 표준 라이브러리에 새 실험적 기능을 가져와요: 공통 원자(atomic) 타입, UUID 지원 개선, 새 시간 추적 기능.
공통 원자 타입
Kotlin 2.1.20에서 표준 라이브러리의 kotlin.concurrent.atomics 패키지에 공통 원자 타입을 도입하여 스레드 안전 작업을 위한 공유되고 플랫폼 독립적인 코드를 가능하게 해요. 이는 소스 세트 전반에 걸쳐 원자 의존 로직을 중복할 필요를 없애 Kotlin Multiplatform 프로젝트 개발을 단순화해요.
kotlin.concurrent.atomics 패키지와 그 프로퍼티는 실험적(Experimental)이에요. 옵트인하려면 @OptIn(ExperimentalAtomicApi::class) 어노테이션이나 -opt-in=kotlin.ExperimentalAtomicApi 컴파일러 옵션을 사용하세요.
AtomicInt를 사용해 여러 스레드에 걸쳐 처리된 항목을 안전하게 계산하는 방법을 보여주는 예시가 있어요.
// Imports the necessary libraries
import kotlin.concurrent.atomics.*
import kotlinx.coroutines.*
//sampleStart
@OptIn(ExperimentalAtomicApi::class)
suspend fun main() {
// Initializes the atomic counter for processed items
var processedItems = AtomicInt(0)
val totalItems = 100
val items = List(totalItems) { "item$it" }
// Splits the items into chunks for processing by multiple coroutines
val chunkSize = 20
val itemChunks = items.chunked(chunkSize)
coroutineScope {
for (chunk in itemChunks) {
launch {
for (item in chunk) {
println("Processing $item in thread ${Thread.currentThread()}")
processedItems += 1 // Increment counter atomically
}
}
}
}
//sampleEnd
// Prints the total number of processed items
println("Total processed items: ${processedItems.load()}")
}
Kotlin의 원자 타입과 Java의 java.util.concurrent.atomic 원자 타입 사이의 원활한 상호 운용을 위해 API는 .asJavaAtomic() 및 .asKotlinAtomic() 확장 함수를 제공해요. JVM에서 Kotlin 원자와 Java 원자는 런타임에 같은 타입이므로 오버헤드 없이 Java 원자를 Kotlin 원자로 또는 그 반대로 변환할 수 있어요.
Kotlin과 Java 원자 타입이 함께 작동할 수 있는 방법을 보여주는 예시가 있어요.
// Imports the necessary libraries
import kotlin.concurrent.atomics.*
import java.util.concurrent.atomic.*
//sampleStart
@OptIn(ExperimentalAtomicApi::class)
fun main() {
// Converts Kotlin's AtomicInt to Java's AtomicInteger
val kotlinAtomic = AtomicInt(42)
val javaAtomic: AtomicInteger = kotlinAtomic.asJavaAtomic()
println("Java atomic value: ${javaAtomic.get()}")
// Java atomic value: 42
// Converts Java's AtomicInteger back to Kotlin's AtomicInt
val kotlinAgain: AtomicInt = javaAtomic.asKotlinAtomic()
println("Kotlin atomic value: ${kotlinAgain.load()}")
// Kotlin atomic value: 42
}
//sampleEnd
UUID 파싱, 포맷, 비교 가능성 변경
JetBrains 팀은 2.0.20에서 표준 라이브러리에 도입된 UUID 지원을 계속 개선하고 있어요.
이전에는 parse() 함수가 hex-and-dash 형식의 UUID만 받아들였어요. Kotlin 2.1.20부터 parse()를 hex-and-dash 형식과 일반 16진수(dash 없는) 형식 모두에 사용할 수 있어요.
또한 이 릴리스에서 hex-and-dash 형식 작업에 특화된 함수를 도입했어요.
parseHexDash()는 hex-and-dash 형식에서 UUID를 파싱해요.toHexDashString()은Uuid를 hex-and-dash 형식의String으로 변환해요(toString()의 기능을 미러링).
이 함수들은 이전에 16진수 형식용으로 도입된 parseHex() 및 toHexString()과 유사하게 작동해요. 파싱 및 포맷 기능에 대한 명시적 명명은 코드 명확성과 UUID 전반적인 경험을 개선해야 해요.
이제 Kotlin의 UUID는 Comparable이에요. Kotlin 2.1.20부터 Uuid 타입의 값을 직접 비교하고 정렬할 수 있어요. 이로 인해 <와 > 연산자와 Comparable 타입이나 그 컬렉션에만 전용으로 사용할 수 있는 표준 라이브러리 확장(예: sorted())을 사용할 수 있고, Comparable 인터페이스를 요구하는 함수나 API에 UUID를 전달할 수도 있어요.
표준 라이브러리의 UUID 지원은 여전히 실험적(Experimental)이라는 점을 기억하세요. 옵트인하려면 @OptIn(ExperimentalUuidApi::class) 어노테이션이나 -opt-in=kotlin.uuid.ExperimentalUuidApi 컴파일러 옵션을 사용하세요.
import kotlin.uuid.ExperimentalUuidApi
import kotlin.uuid.Uuid
//sampleStart
@OptIn(ExperimentalUuidApi::class)
fun main() {
// parse() accepts a UUID in a plain hexadecimal format
val uuid = Uuid.parse("550e8400e29b41d4a716446655440000")
// Converts it to the hex-and-dash format
val hexDashFormat = uuid.toHexDashString()
// Outputs the UUID in the hex-and-dash format
println(hexDashFormat)
// Outputs UUIDs in ascending order
println(
listOf(
uuid,
Uuid.parse("780e8400e29b41d4a716446655440005"),
Uuid.parse("5ab88400e29b41d4a716446655440076")
).sorted()
)
}
//sampleEnd
새 시간 추적 기능
Kotlin 2.1.20부터 표준 라이브러리는 한 순간의 시간을 나타내는 기능을 제공해요. 이 기능은 이전에 공식 Kotlin 라이브러리인 kotlinx-datetime에서만 사용할 수 있었어요.
kotlinx.datetime.Clock 인터페이스가 표준 라이브러리에 kotlin.time.Clock으로, kotlinx.datetime.Instant 클래스가 kotlin.time.Instant으로 도입됐어요. 이 개념들은 시간의 순간에만 관련되므로 표준 라이브러리의 time 패키지와 자연스럽게 일치하며, 더 복잡한 달력 및 시간대 기능은 kotlinx-datetime에 남아 있어요.
Instant와 Clock은 시간대나 날짜를 고려하지 않고 정밀한 시간 추적이 필요할 때 유용해요. 예를 들어 이벤트를 타임스탬프로 기록하고, 두 시점 사이의 기간을 측정하고, 시스템 프로세스의 현재 순간을 얻는 데 사용할 수 있어요.
다른 언어와의 상호 운용을 위해 추가 변환 함수를 사용할 수 있어요.
.toKotlinInstant()는 시간 값을kotlin.time.Instant인스턴스로 변환해요..toJavaInstant()는kotlin.time.Instant값을java.time.Instant값으로 변환해요.Instant.toJSDate()는kotlin.time.Instant값을 JSDate클래스의 인스턴스로 변환해요. 이 변환은 정밀하지 않아요. JS는 날짜를 나타낼 때 밀리초 정밀도를 사용하는 반면 Kotlin은 나노초 해상도를 허용하기 때문이에요.
표준 라이브러리의 새 시간 기능은 여전히 실험적(Experimental)이에요. 옵트인하려면 @OptIn(ExperimentalTime::class) 어노테이션을 사용하세요.
import kotlin.time.*
@OptIn(ExperimentalTime::class)
fun main() {
// Get the current moment in time
val currentInstant = Clock.System.now()
println("Current time: $currentInstant")
// Find the difference between two moments in time
val pastInstant = Instant.parse("2023-01-01T00:00:00Z")
val duration = currentInstant - pastInstant
println("Time elapsed since 2023-01-01: $duration")
}
구현에 대한 자세한 내용은 이 KEEP 제안을 참고하세요.
Compose 컴파일러
2.1.20에서 Compose 컴파일러는 이전 릴리스에서 도입된 @Composable 함수에 대한 일부 제한을 완화해요. 또한 Compose 컴파일러 Gradle 플러그인은 모든 플랫폼에서 Android와 동작을 맞추기 위해 기본적으로 소스 정보를 포함하도록 설정됐어요.
open @Composable 함수에서 기본값이 있는 매개변수 지원
컴파일러는 이전에 잘못된 컴파일러 출력으로 인해 open @Composable 함수에서 기본값이 있는 매개변수를 제한했으며, 이는 런타임에서 충돌을 초래할 수 있었어요. 근본적인 문제는 이제 해결됐으며, 기본값이 있는 매개변수는 Kotlin 2.1.20 이상을 사용할 때 완전히 지원돼요.
Compose 컴파일러는 이전 버전 1.5.8 이전에는 open 함수에서 기본값이 있는 매개변수를 허용했으므로 지원 여부는 프로젝트 구성에 따라 달라요.
- open composable 함수가 Kotlin 2.1.20 이상으로 컴파일되면 컴파일러는 기본값이 있는 매개변수에 대한 올바른 래퍼를 생성해요. 여기에는 pre-1.5.8 바이너리와 호환되는 래퍼가 포함되므로 다운스트림 라이브러리도 이 open 함수를 사용할 수 있게 돼요.
- open composable 함수가 2.1.20보다 오래된 Kotlin으로 컴파일되면 Compose는 호환성 모드를 사용하며, 이로 인해 런타임 충돌이 발생할 수 있어요. 호환성 모드를 사용할 때 컴파일러는 잠재적 문제를 강조하기 위해 경고를 내보내요.
final로 재정의된 함수가 restartable이 될 수 있음
가상 함수(open과 abstract의 재정의, 인터페이스 포함)는 2.1.0 릴리스에서 non-restartable이도록 강제됐어요. 이 제한은 now final 클래스의 멤버이거나 그 자체가 final인 함수에 대해 완화됐으며, 이들은 평소처럼 재시작되거나 스킵돼요.
Kotlin 2.1.20으로 업그레이드한 후 영향을 받는 함수에서 일부 동작 변화를 관찰할 수 있어요. 이전 버전의 non-restartable 로직을 강제하려면 함수에 @NonRestartableComposable 어노테이션을 적용하세요.
ComposableSingletons가 공개 API에서 제거됨
ComposableSingletons는 Compose 컴파일러가 @Composable 람다를 최적화할 때 생성하는 클래스예요. 매개변수를 캡처하지 않는 람다는 한 번 할당되고 클래스의 프로퍼티에 캐시되어 런타임 중 할당을 절약해요. 클래스는 내부 가시성으로 생성되며 컴파일 단위(보통 파일) 안의 람다 최적화만을 위한 것이에요.
하지만 이 최적화는 inline 함수 본문에도 적용되어 싱글턴 람다 인스턴스가 공개 API로 누출됐어요. 이 문제를 해결하기 위해 2.1.20부터 @Composable 람다는 더 이상 inline 함수 안에서 싱글턴으로 최적화되지 않아요. 동시에 Compose 컴파일러는 이전 모델로 컴파일된 모듈에 대한 이진 호환성을 지원하기 위해 inline 함수에 대한 싱글턴 클래스와 람다를 계속 생성할 거예요.
기본으로 포함되는 소스 정보
Compose 컴파일러 Gradle 플러그인은 이미 Android에서 소스 정보 포함 기능을 기본으로 활성화했어요. Kotlin 2.1.20부터 이 기능은 모든 플랫폼에서 기본으로 활성화될 거예요.
freeCompilerArgs를 사용해 이 옵션을 설정했는지 확인하세요. 이 방법은 플러그인과 함께 사용할 때 옵션이 사실상 두 번 설정되어 빌드가 실패할 수 있어요.
Breaking changes 및 사용 중단
- Kotlin Multiplatform을 Gradle의 예정된 변경과 맞추기 위해
withJava()함수를 단계적으로 없애고 있어요. Java 소스 세트는 이제 기본으로 생성돼요. Java test fixtures Gradle 플러그인을 사용한다면 호환성 문제를 피하기 위해 Kotlin 2.1.21로 직접 업그레이드하세요. - JetBrains 팀은
kotlin-android-extensions플러그인의 사용 중단을 진행하고 있어요. 프로젝트에서 이를 사용하려고 하면 이제 구성 오류가 발생하며 어떤 플러그인 코드도 실행되지 않아요. - 레거시
kotlin.incremental.classpath.snapshot.enabled프로퍼티가 Kotlin Gradle 플러그인에서 제거됐어요. 이 프로퍼티는 JVM에서 내장 ABI 스냅샷으로 폴백할 수 있는 기회를 제공하는 데 사용됐어요. 플러그인은 이제 불필요한 재컴파일을 감지하고 피하기 위해 다른 방법을 사용하므로 이 프로퍼티는 더 이상 사용되지 않아요.
문서 업데이트
Kotlin 문서에 몇 가지 눈에 띄는 변경이 있었어요.
개편되고 새로운 페이지
- Kotlin 로드맵 - 언어 및 생태계 진화에 대한 Kotlin의 우선 순위 업데이트 목록을 확인하세요.
- Gradle 모범 사례 페이지 - Gradle 빌드를 최적화하고 성능을 개선하기 위한 필수 모범 사례를 배우세요.
- Compose Multiplatform과 Jetpack Compose - 두 UI 프레임워크의 관계에 대한 개요.
- Kotlin Multiplatform과 Flutter - 두 인기 크로스 플랫폼 프레임워크의 비교를 확인하세요.
- C와의 상호 운용성 - Kotlin과 C의 상호 운용성 세부 사항을 살펴보세요.
- 숫자 - 숫자를 나타내는 다양한 Kotlin 타입에 대해 배우세요.
새롭고 업데이트된 튜토리얼
- Maven Central에 라이브러리 게시 - KMP 라이브러리 아티팩트를 가장 인기 있는 Maven 저장소에 게시하는 방법을 배우세요.
- 동적 라이브러리로서의 Kotlin/Native - 동적 Kotlin 라이브러리를 만드세요.
- Apple 프레임워크로서의 Kotlin/Native - 자체 프레임워크를 만들고 macOS 및 iOS의 Swift/Objective-C 애플리케이션에서 Kotlin/Native 코드를 사용하세요.
Kotlin 2.1.20으로 업데이트하는 방법
IntelliJ IDEA 2023.3과 Android Studio Iguana (2023.2.1) Canary 15부터 Kotlin 플러그인은 IDE에 포함된 번들 플러그인으로 배포돼요. 즉, 더 이상 JetBrains Marketplace에서 플러그인을 설치할 수 없어요.
새 Kotlin 버전으로 업데이트하려면 빌드 스크립트에서 Kotlin 버전을 2.1.20으로 변경하세요.