App desugaring(= Java 8+ AP#I / core library desugaring)์ด โ๋ฌด์์โ ํด๊ฒฐํ๋ ๋ฐฉ์์ธ๊ฐ
Android ์ฑ์ JVM์ด ์๋๋ผ ART(Android Runtime) ์์์ ์คํ๋ฉ๋๋ค. ๊ทธ๋์ ๋น๋ ๊ฒฐ๊ณผ๋ฌผ์ โJVM ๋ฐ์ดํธ์ฝ๋(.class)โ๊ฐ ์๋๋ผ,
ART๊ฐ ์คํํ๋ ๋ฐ์ดํธ์ฝ๋ ํฌ๋งท(DEX) ๋ก ํจํค์ง๋์ด์ผ ํฉ๋๋ค.
์ด ๊ณผ์ ์ ๋ณดํต D8/R8์ด .class โ .dex๋ก ์ปดํ์ผ(dexing) ํ๋ฉด์ ์ํํฉ๋๋ค.
๋ฌธ์ ๋, Android๊ฐ OS ๋ฒ์ (API ๋ ๋ฒจ)์ ๋ฐ๋ผ ์ ๊ณตํ๋ Java ํ์ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ API ๋ฒ์๊ฐ ๋ค๋ฅด๋ค๋ ์ ์
๋๋ค.
์๋ฅผ ๋ค์ด java.util.stream.* ๊ฐ์ API๋ ๋ฎ์ OS์ ์๊ธฐ ๋๋ฌธ์, ํด๋น API๋ฅผ ์ฌ์ฉํ๋ ์ฝ๋(๋ด ์ฝ๋๋ 3rd party๋ )๊ฐ ์คํ๋๋ฉด
๋ํ์ ์ผ๋ก NoClassDefFoundError/ClassNotFoundException ๋ฅ์ ๋ฐํ์ ์ค๋ฅ๊ฐ ๋ฐ์ํ ์ ์์ต๋๋ค.
App desugaring(๊ณต์ ๋ช ์นญ: Java 8+ API desugaring / core library desugaring) ์ ์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด
- (1) ์ฑ์ โ๋ถ์กฑํ Java ํ์ค API ๊ตฌํโ์ ๊ฐ์ด ๋ฒ๋ค๋ง(์ค์ ๋ก๋ desugared library๊ฐ ํฌํจ๋ DEX/ํด๋์ค๋ค์ด ์ฑ์ ๋ค์ด์ด)ํ๊ณ
- (2) ์ปดํ์ผ ๋จ๊ณ์์ ํธ์ถ ์ง์ ์ ๋ฆฌ๋ผ์ดํธ(rewrite) ํด์
- (3) ๋ฐํ์์ โํ๋ซํผ์ ์๋ APIโ๋ฅผ ์ฑ์ด ํฌํจํ ๊ตฌํ์ผ๋ก ๋์ฒด(backport) ํ์ฌ ์ฌ์ฉํ๊ฒ ๋ง๋๋ ๊ธฐ๋ฅ์ ๋๋ค.
์์ฝ: โOS์ ์๋ Java ํ์ค API๋ฅผ ์ฑ์ด ํจ๊ป ๋ค๊ณ ๊ฐ์(backport) ์คํ๋๊ฒ ํ๋ค.โ
desugar๋ฅผ ์ดํดํ๊ธฐ ์ํ Q&A (๊ผฌ๋ฆฌ ์ง๋ฌธ ํฌํจ)
Q1. ์ .class๋ฅผ ๊ทธ๋๋ก ์ฐ์ง ์๊ณ .dex๋ก ๋ง๋๋? (AGP๊ฐ ๊ตณ์ด ๋ณํํ๋ ์ด์ )
A. Android ๊ธฐ๊ธฐ์์ ์ฑ์ JVM์ด ์๋๋ผ ART๊ฐ ์คํํฉ๋๋ค. ART๋ JVM .class๋ฅผ ์ง์ ์คํํ๋ ๊ฒ ์๋๋ผ, ์ฑ์ด ํจํค์งํ DEX ๋ฐ์ดํธ์ฝ๋๋ฅผ ์คํํฉ๋๋ค.
๊ทธ๋์ ๋น๋ ํ์ดํ๋ผ์ธ์ ํ์์ ์ผ๋ก .class โ .dex ์ปดํ์ผ์ ์ํํฉ๋๋ค. ์ด ์ญํ ์ D8(๋๋ R8)์ด ํฉ๋๋ค.
๊ฐ๋ฐ์ ๊ด์ ์์ฝ:
.class โ .dex๋ โXMLโJSON ๊ฐ์ ๋จ์ ํฌ๋งท ์นํโ์ ๊ฐ๊น๊ธฐ๋ณด๋จ, ์คํ ๋จธ์ ์ด ๋ค๋ฅธ ํ๊ฒฝ(ART)์ ์ํ ์ปดํ์ผ์ ๊ฐ๊น์ต๋๋ค.
Q2. ๊ทธ๋ฌ๋ฉด โdesugarโ๋ .class โ .dex ๋ณํ ์์ฒด๋ฅผ ์๋ฏธํ๋?
A. ์ ํํ๋ ์๋๋๋ค.
- dexing:
.class โ .dex๋ก โART ์คํ ํฌ๋งทโ์ ๋ง๋๋ ์ปดํ์ผ ์์ (D8/R8์ ์ญํ ) - desugaring: dexing ๊ณผ์ ์์(๋๋ ๊ทธ ์ง์ /์งํ์) ํธํ์ฑ ํ๋ณด๋ฅผ ์ํด ๋ฐ์ดํธ์ฝ๋๋ฅผ ์ถ๊ฐ ๋ณํ/๋ฆฌ๋ผ์ดํธํ๋ ์์
์ฆ, desugar๋ โdex๋ก ๋ฐ๊พธ๋ ๊ฒโ์ด ์๋๋ผ dex๋ก ๋ฐ๊พธ๋ ๊ณผ์ ์ ๋ผ์ด๋๋ โ์ถ๊ฐ ๋ณํโ์ด๋ผ๊ณ ๋ณด๋ ๊ฒ ์ ํํฉ๋๋ค.
Q3. โ๋ฎ์ ๋ฐํ์์์๋ ๋์ํ๋คโ๋ ๊ฒ ๋ฌด์จ ๋ป?
A. โ๋ฎ์ ๋ฐํ์โ์ ๋ณดํต **๋ฎ์ Android API ๋ ๋ฒจ(= ์ค๋๋ OS)**์ ๋ปํฉ๋๋ค. ๋ฎ์ OS์์๋
-
์ธ์ด ๊ธฐ๋ฅ: (์: ๋๋ค, default interface method ๋ฑ) ํน์ ๋ฐ์ดํธ์ฝ๋ ํจํด์ด ๊ทธ๋๋ก ์ ์ง๋๋ฉด ์์ ํ์ง ์์ ์ ์์ด D8/R8์ด โ๋ ๋จ์ํ ํํโ๋ก ํ์ด์ฃผ๋ ๋ณํ์ด ํ์ํฉ๋๋ค.
โ ์ด๊ฑธ ํํ ์ธ์ด ๊ธฐ๋ฅ desugaring์ด๋ผ๊ณ ๋ถ๋ฆ ๋๋ค. -
ํ์ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ API: (์:
java.util.stream,java.time์ผ๋ถ) OS์ ํด๋์ค ์์ฒด๊ฐ ์์ด์ ๊ทธ๋๋ก ์คํํ๋ฉด NoClass ์๋ฌ๊ฐ ๋ฉ๋๋ค.
โ ์ด๊ฑธ ํด๊ฒฐํ๊ธฐ ์ํด โ์ฑ์ด ๊ตฌํ์ ํฌํจ + ํธ์ถ์ ๊ทธ ๊ตฌํ์ผ๋ก ๋ฐ๊ฟโ์ด ํ์ํ๊ณ , ๊ทธ๊ฒ core library desugaring(App desugaring) ์ ๋๋ค.
ํ ์ค ์์ฝ:
- ์ธ์ด desugar: โ๋ฌธ๋ฒ/๋ฐ์ดํธ์ฝ๋ ํจํดโ์ ๋ฎ์ ํ๊ฒฝ์์๋ ๋๊ฒ ๋ณํ
- API desugar: โ์๋ ํ์ค API ๊ตฌํโ์ ์ฑ์ ํฌํจ + ํธ์ถ ๋ฆฌ๋ผ์ดํธ
Q4. core library desugaring์ โํจํค์ง๋ช ์ ์ ํจํค์ง๋ก ์ฐ๊ฒฐ(alias)โํด์ฃผ๋ ๊ฑด๊ฐ?
A. โ๋ณ์นญ(alias)๋ก ์ฐ๊ฒฐโ์ด๋ผ๊ธฐ๋ณด๋ค๋, ํ๋ซํผ(java.*)๊ณผ ์ถฉ๋์ ํผํ๊ธฐ ์ํ ๋ค์์คํ์ด์ค/๋ฆฌ๋ผ์ดํธ ์ ๋ต์ ๊ฐ๊น์ต๋๋ค.
- Android ํ๋ซํผ์
java.*๋ bootclasspath์ ์๊ณ ์ฑ์ด ์ด๋ฅผ โ๋ฎ์ด์ฐ๊ธฐโํ ์ ์์ต๋๋ค. - ๊ทธ๋์ desugared library ๊ตฌํ์ ์ถฉ๋ ํํผ๋ฅผ ์ํด ๋ณ๋ ๋ค์์คํ์ด์ค(์:
j$.*)๋ก ๋ค์ด์ค๊ฑฐ๋, ๊ท์น์ ๋ฐ๋ผ ํน์ prefix๋ฅผ rewriteํ๋ ๋ฐฉ์์ผ๋ก ๋์ํฉ๋๋ค. - ์ผ๋ถ ์ผ์ด์ค๋ ์ต์ OS์์๋ ํ๋ซํผ ํด๋์ค๊ฐ ์ฐ์ ์ฌ์ฉ๋๊ณ (bootclasspath ์ฐ์ ), ๋ฎ์ OS์์๋ desugared ๊ตฌํ์ด ์ฌ์ฉ๋๊ธฐ๋ ํฉ๋๋ค. (์ด๊ฑด ์ฝ๋ ๋ถ๊ธฐ๋ผ๊ธฐ๋ณด๋ค๋ โ์ด๋ค ํด๋์ค๋ฅผ ๋ก๋ฉํ๋๋โ์ ์ฑ๊ฒฉ)
Q5. ๊ทธ๋ผ DEX ์์๋ Android ๋ฒ์ ๋ณ ๋ถ๊ธฐ(if SDK_INTโฆ)๊ฐ ์๋ฉ ๋ค์ด๊ฐ๋?
A. ๋ณดํต์ ์๋๋๋ค. ํต์ฌ์ โ๋ฐํ์์์ minSdk๋ฅผ ํ์ธํด ๋ญ๊ฐ๋ฅผ ์ถ๊ฐโ๊ฐ ์๋๋ผ,
- ๋น๋ ์์ ์ ์ด๋ฏธ minSdk๊ฐ ์ ํด์ ธ ์๊ณ , ๊ทธ ๊ฐ์ ๋ง์ถฐ D8/R8์ด ๋ณํ/๋ฆฌ๋ผ์ดํธ/๋ผ์ด๋ธ๋ฌ๋ฆฌ ํฌํจ์ ์ํํด
- APK์ ๊ณ ์ ๋ ๊ฒฐ๊ณผ๋ฌผ๋ก ๋ค์ด๊ฐ๋๋ค.
๋ค๋ง core library desugaring์ โํด๋์ค ๋ก๋ฉ ์ฐ์ ์์(ํ๋ซํผ ์ฐ์ )โ ๊ฐ์ ์ด์ ๋ก
๊ฒฐ๊ณผ์ ์ผ๋ก OS์ ๋ฐ๋ผ ๋ค๋ฅธ ๊ตฌํ์ด ์ฌ์ฉ๋๋ ๊ฒ์ฒ๋ผ ๋ณด์ผ ์๋ ์์ต๋๋ค(ํ์ง๋ง ์ผ๋ฐ์ ์ธ if (SDK_INT >= โฆ) ๋ถ๊ธฐ ์ฝ๋๊ฐ ์ฆ๊ฐํ๋ ํํ๋ ํ์น ์์).
์(์ธ์ ) ํ์ํ๊ฐ
์๋ ์ค ํ๋๋ผ๋ ํด๋นํ๋ฉด โAPI desugaringโ์ด ํ์ํด์ง ์ ์์ต๋๋ค.
- ๋ด ์ฝ๋๊ฐ Java 8+ API๋ฅผ ์ง์ ์ฌ์ฉํด์ผ ํ๋ค.
- ์: Stream API(
java.util.stream) ๋ฑ
- ์: Stream API(
- ์์กด ๋ผ์ด๋ธ๋ฌ๋ฆฌ(3rd party)๊ฐ Java 8+ API๋ฅผ ์ฌ์ฉํ๋ค.
- ์ฑ์ด ์ง์ ์ ์ฐ๋๋ผ๋ ์์กด์ฑ ๋ด๋ถ ํธ์ถ ๋๋ฌธ์ ๋ฐํ์/๊ฒ์ฆ ๋ฌธ์ ๊ฐ ๋ฐ์ํ ์ ์์
- ํน์ SDK๊ฐ โcore library desugaring์ ํ์ ๋น๋ ์๊ฑดโ์ผ๋ก ์๊ตฌํ๋ค.
- ์ด ๊ฒฝ์ฐ๋ โOS ๋ฏธ์ง์โ๊ณผ ๋ณ๊ฐ๋ก, โSDK ๋ฆด๋ฆฌ์ฆ ์ ์ฑ /๋น๋ ๊ฐ์ โ ๋๋ฌธ์ ์ ๊ทธ๋ ์ด๋๊ฐ ๋งํ ์ ์์
์ฐธ๊ณ : โJava 8 ์ธ์ด ๊ธฐ๋ฅ(๋๋ค ๋ฑ)โ์ ๊ธฐ๋ณธ desugar(์ธ์ด ๊ธฐ๋ฅ)๋ก ํด๊ฒฐ๋๊ณ ,
์ฌ๊ธฐ์ ๋งํ๋ โApp desugaringโ์ ํ์ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ API(ํด๋์ค/๋ฉ์๋)๊น์ง ํ์ฅ(backport)ํ๋ ๊ธฐ๋ฅ์ ์๋ฏธํฉ๋๋ค.
(๊ณต์ ๋ฌธ์ ๊ด์ ) App desugaring์ด ์ค์ ๋ก ํ๋ ์ผ
Android Gradle Plugin(AGP)์์ API desugaring์ ์ผ๋ฉด:
- missing API ๊ตฌํ์ ํฌํจํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ(desugared library)๋ฅผ ์ฑ์ ํฌํจํฉ๋๋ค.
- desugaring ๊ณผ์ ์์ ์ฑ์ ํธ์ถ ์ง์ ์ ๋ณํ(rewrite) ํ์ฌ, ๋ฐํ์์ ๊ทธ ๊ตฌํ์ ์ฐ๊ฒ ํฉ๋๋ค.
- ์ ๊ณต๋๋ API ๋ฒ์๋
desugar_jdk_libs(๋ฐ AGP/๋ฒ์ )์ ๋ฐ๋ผ ๋ฌ๋ผ์ง๋๋ค.
์ค์ (์์)
์๋๋ ๊ณต์ ๋ฌธ์์ ๋ํ ์ค์ ํํ๋ฅผ ๊ทธ๋๋ก ์์ฝํ ์์์ ๋๋ค.
Kotlin DSL (build.gradle.kts)
android {
compileOptions {
// AGP 4.1+
isCoreLibraryDesugaringEnabled = true
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
}
dependencies {
coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.0.3")
}๋์ผ๋ก ๋ณด๋ ์ฆ๊ฑฐ(โ์ ๋ง ๋ญ๊ฐ ์ถ๊ฐ๋๊ณ , ๋ญ๊ฐ ๋ฐ๋๋?โ)
์๋๋ ํ๋ก์ ํธ์์ ๋ฐ๋ก ํ์ธ ๊ฐ๋ฅํ ์ฒดํฌ๋ฆฌ์คํธ์ ๋๋ค.
1) APK์ โ์ถ๊ฐ๋ ํ์ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๊ตฌํโ์ด ๋ค์ด์๋์ง
- Android Studio Analyze APK ๋๋
jadx๋ก APK ์ด๊ธฐ - ํด๋์ค ๊ฒ์:
j$/util/stream/j$/time/j$/util/function/โ ์ด๋ฐ ํจํค์ง๊ฐ ๋ณด์ด๋ฉด โํ๋ซํผ์ ์๋ API ๊ตฌํ์ด ์ฑ์ ๋ฒ๋ค๋ง๋์๋คโ๋ ๊ฐํ ์ฆ๊ฑฐ์ ๋๋ค.
2) ํธ์ถ์ด rewrite ๋์๋์ง(์์ค๋ java.util.stream์ธ๋ฐ ๊ฒฐ๊ณผ๋ฌผ์?)
stream()/java.util.stream์ฌ์ฉ ์ง์ ์ ๋์ปดํ์ผํด์ ํ์ธ- desugaring์ด ์ ์ฉ๋ ๊ฒฝ์ฐ, ๋ด๋ถ์ ์ผ๋ก
j$.util.stream๊ณ์ด ํธ์ถ ํ์ ์ด ๋ณด์ด๋ ๊ฒฝ์ฐ๊ฐ ๋ง์ต๋๋ค.
3) ์ธ์ด desugar ํ์ (๋๋ค ๋ฑ)
- ๊ฒฐ๊ณผ๋ฌผ์์
$$ExternalSyntheticLambda/$$Lambda$...๊ฐ์ synthetic ํด๋์ค ํ์ ์ ํ์ธ โ โ๋๋ค๊ฐ ์ํ ๊ทธ๋๋กโ๊ฐ ์๋๋ผ, ๋ฎ์ ํ๊ฒฝ์์๋ ์์ ํ ํํ๋ก ํ๋ ธ๋ค๋ ๋จ์์ ๋๋ค.
์ค๋ฌด์์ ์ฒดํฌํด์ผ ํ๋ ์ํฅ(๋ฆฌ์คํฌ/์ด์ ํฌ์ธํธ)
์๋๋ โ๊ธฐ๋ฅ ์์ฒดโ๊ฐ ์๋๋ผ, ๋์ ์ ํํ ๋ถ๋ชํ๋ ์ด์ ํฌ์ธํธ์ ๋๋ค.
- ์ฑ ์ฌ์ด์ฆ/๋ฉ์๋ ์ ์ฆ๊ฐ ๊ฐ๋ฅ์ฑ
- ๋ฒ๋ค๋ง๋๋ API ๋ฒ์๊ฐ ๋์์๋ก ์ฝ๋ ์ฌ์ด์ฆ ์ํฅ์ด ์ปค์ง ์ ์์
- ํ
์คํธ ๋ฒ์ ํ๋
- desugared ๊ตฌํ + ํธ์ถ ๋ฆฌ๋ผ์ดํธ๊ฐ ๋ค์ด๊ฐ๋ฏ๋ก, ๋จ๋ง/OS ์กฐํฉ ํ ์คํธ ํ์
- ๋ฆฌํ๋ ์
/ํด๋์ค ์ถฉ๋ ๋ฆฌ์คํฌ
- (ํนํ
java.*/javax.*์ ๊ทผ์ ๋ฆฌํ๋ ์ ์ผ๋ก ๋ค๋ฃจ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์กฐํฉ์์) ์์์น ๋ชปํ ๋์ ๊ฐ๋ฅ์ฑ
- (ํนํ
- ์ตํธ์ธ ํ ์ตํธ์์์ด ์ฝ์ง ์์ ์ ์์
- ์ฌ๋ฌ ๋ชจ๋/์ธ๋ถ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ desugared API ์ฌ์ฉ์ ์์กดํ๊ธฐ ์์ํ๋ฉด ๋๋๋ฆฌ๊ธฐ ๋น์ฉ์ด ์ปค์ง
์ฐธ๊ณ (๊ณต์ ๋ฌธ์/๋ ํผ๋ฐ์ค)
- Android Developers: Use Java 8 language features and APIs
- Android Developers Blog: API desugaring (desugar_jdk_libs ์คํ/์ฌ์ด์ฆ ์ํฅ)
- Android Developers: Java 11+ APIs available through desugaring (์ง์ API ํ ์ด๋ธ)
- Google IMA Android SDK release history (3.37.0์์ โapp desugaring requirementโ ๋ช ์)