Wispλ Jetpack Composeμ νμ μΈμ΄ν λ€λΉκ²μ΄μ νκ²½μμ, μλ²κ° λμ μΌλ‘ μ μνλ λ°±μ€νμ νλ©΄ κΉλΉ‘μ μμ΄ μμ½κ² νμν μ μκ² ν΄μ£Όλ μ΄λ Έν μ΄μ κΈ°λ° λ₯λ§ν¬ λΌμ΄λΈλ¬λ¦¬μ λλ€.
Jetpack Compose νκ²½μμ navigation-composeμ κΈ°λ³Έ λ₯λ§ν¬λ μ μ μΈ λ°±μ€νλ§ μμ±ν μ μμ΄, μλ²κ° λμ μΌλ‘ μ¬μ©μ μ¬μ (User Journey)μ μ μ΄νλ €λ μꡬμ¬νμ μΆ©μ‘±νκΈ° μ΄λ ΅μ΅λλ€. Wispλ μ΄ κ³Όμ μ μλννμ¬ κ°λ°μκ° μ€μ§ λΌμ°νΈ μ μμλ§ μ§μ€ν μ μλλ‘ λμ΅λλ€.
- μλ² μ£Όλ (Server-Driven): λ°±μ€ν ꡬμ±μ λͺ¨λ κΆνμ μλ²κ° κ°μ΅λλ€.
- λ¨μν¨ (Simplicity): κ°λ°μλ λΌμ°νΈ ν΄λμ€ μ μμ μ΄λ Έν μ΄μ μΆκ° μΈμ 볡μ‘ν λ‘μ§μ μ κ²½ μ°μ§ μμ΅λλ€.
- μ μ°μ± (Flexibility): URI νμ± λ‘μ§μ μΈλΆμμ μ£Όμ ν μ μμ΄, μ΄λ€ ννμ λ₯λ§ν¬ URI μ€ν΄(Scheme)μ΄λΌλ μ§μν μ μμ΅λλ€.
1. build.gradle.kts (Project Level)
settings.gradle.ktsκ° μλ νλ‘μ νΈ λ 벨μ build.gradle.ktsμ KSP νλ¬κ·ΈμΈμ μΆκ°ν©λλ€.
plugins {
// ...
alias(libs.plugins.ksp) apply false
}2. build.gradle.kts (App Module Level)
app λͺ¨λμ build.gradle.ktsμ νλ¬κ·ΈμΈκ³Ό μμ‘΄μ±μ μΆκ°ν©λλ€.
plugins {
// ...
alias(libs.plugins.ksp)
}
dependencies {
// Wisp
implementation(project(":wisp-runtime"))
ksp(project(":wisp-processor"))
// ... κΈ°ν μμ‘΄μ±
}@Serializable μ΄λ
Έν
μ΄μ
μ΄ λΆμ data class λλ objectμ @Wisp μ΄λ
Έν
μ΄μ
μ μΆκ°νμ¬ λ₯λ§ν¬ λμμΌλ‘ μ§μ ν©λλ€.
// app/src/main/java/com/example/app/Routes.kt
import com.angrypodo.wisp.annotations.Wisp
import kotlinx.serialization.Serializable
@Serializable
@Wisp("home")
data object Home
@Serializable
@Wisp("product/{productId}")
data class ProductDetail(val productId: String)
@Serializable
@Wisp("settings")
data object SettingsApplication ν΄λμ€μ onCreate()μμ, KSPκ° μμ±ν WispRegistryλ₯Ό μ¬μ©νμ¬ Wisp λΌμ΄λΈλ¬λ¦¬λ₯Ό μ΄κΈ°νν©λλ€.
// app/src/main/java/com/example/app/MyApplication.kt
import android.app.Application
import com.angrypodo.wisp.generated.WispRegistry
import com.angrypodo.wisp.runtime.Wisp
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
Wisp.initialize(WispRegistry)
}
}μ£Όμ: AndroidManifest.xmlμ <application> νκ·Έμ android:name=".MyApplication" μμ±μ μΆκ°νλ κ²μ μμ§ λ§μΈμ.
Compose Activityμμ NavHostλ₯Ό μ€μ νκ³ , μ μν λΌμ°νΈμ Composable νλ©΄μ μ°κ²°ν©λλ€.
// app/src/main/java/com/example/app/MainActivity.kt
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
val navController = rememberNavController()
NavHost(navController = navController, startDestination = Home) {
composable<Home> { HomeScreen(navController) }
composable<ProductDetail> { backStackEntry ->
val product = backStackEntry.toRoute<ProductDetail>()
ProductDetailScreen(product.productId)
}
composable<Settings> { SettingsScreen() }
}
}
}
}μ΄μ μ±μ μ΄λ κ³³μμλ NavControllerλ§ μλ€λ©΄ navigateTo(uri) νμ₯ ν¨μλ₯Ό μ¬μ©νμ¬ λμ λ°±μ€νμ νμν μ μμ΅λλ€.
- URI νμ:
scheme://host?stack={encoded_stack} stackνλΌλ―Έν°:- κ°λ³ λ°±μ€ν κ²½λ‘λ
|λ¬Έμλ‘ κ΅¬λΆν©λλ€. - URL μΈμ½λ©μ΄ νμν μ μμ΅λλ€.
- κ°λ³ λ°±μ€ν κ²½λ‘λ
// HomeScreen.kt μμ λ²νΌ ν΄λ¦ μ λ₯λ§ν¬ μ€ν
Button(onClick = {
// λ°±μ€ν: ProductDetail(productId="123") -> Settings
val uri = "app://wisp?stack=product/123|settings".toUri()
navController.navigateTo(uri)
}) {
Text("Deep Link Navigation")
}