plugins { // AGP must apply before recipe.kotlin.multiplatform — the latter calls androidTarget(), // which requires the Android Gradle Plugin to already be on the project. alias(libs.plugins.androidApplication) id("recipe.kotlin.multiplatform") alias(libs.plugins.composeMultiplatform) alias(libs.plugins.composeCompiler) alias(libs.plugins.composeHotReload) alias(libs.plugins.kotlinSerialization) id("recipe.quality") } // `group` is referenced by Compose Resources package naming — the // `compose.resources { packageOfResClass }` block below pins the historical package // regardless, but keep `group` set explicitly. Gradle artifact metadata only. group = "dev.ulfrx.recipe" version = "1.0.0" android { namespace = "dev.ulfrx.recipe" compileSdk = libs.versions.android.compileSdk .get() .toInt() defaultConfig { applicationId = "dev.ulfrx.recipe" minSdk = libs.versions.android.minSdk .get() .toInt() targetSdk = libs.versions.android.targetSdk .get() .toInt() versionCode = 1 versionName = "1.0" // Lokksmith's Android redirect activity uses the scheme-only placeholder. // Must match `dev.ulfrx.recipe.shared.Constants.OIDC_REDIRECT_URI`. manifestPlaceholders["lokksmithRedirectScheme"] = "recipe" } packaging { resources { excludes += "/META-INF/{AL2.0,LGPL2.1}" } } buildTypes { getByName("release") { isMinifyEnabled = false } } compileOptions { sourceCompatibility = JavaVersion.VERSION_11 targetCompatibility = JavaVersion.VERSION_11 } } kotlin { sourceSets { commonMain.dependencies { implementation(project.dependencies.platform(libs.koin.bom)) implementation(libs.koin.core) implementation(libs.koin.compose) implementation(libs.koin.composeViewmodel) implementation(libs.kermit) implementation(libs.compose.runtime) implementation(libs.compose.foundation) implementation(libs.compose.material3) implementation(libs.compose.ui) implementation(libs.compose.components.resources) implementation(libs.compose.uiToolingPreview) implementation(libs.androidx.lifecycle.viewmodelCompose) implementation(libs.androidx.lifecycle.runtimeCompose) // `api` so `:shared` types flow through to the exported ObjC // framework headers when the iOS shell needs them. api(projects.shared) // Phase 2: Ktor client + serialization + secure settings (D-13, D-16, D-17). // The MPP variant of `ktor-serialization-kotlinx-json` is required here; the // server module keeps the `-jvm` variant via `libs.ktor.serializationKotlinxJson`. implementation(libs.ktor.clientCore) implementation(libs.ktor.clientAuth) implementation(libs.ktor.clientContentNegotiation) implementation(libs.ktor.clientLogging) implementation(libs.ktor.serializationKotlinxJsonMpp) implementation(libs.kotlinx.serializationJson) implementation(libs.multiplatform.settings) implementation(libs.multiplatform.settings.coroutines) } commonTest.dependencies { // 02-07: kotlinx.coroutines.test.runTest is the multiplatform-safe // alternative to runBlocking (which is JVM/Native-only and breaks the // wasmJs test target). All commonTest coroutine tests use it. implementation(libs.kotlinx.coroutinesTest) } androidMain.dependencies { implementation(libs.compose.uiToolingPreview) implementation(libs.androidx.activity.compose) implementation(libs.koin.android) // Phase 2 Android: AndroidX Security Crypto for the SecureAuthStateStore // actual (D-13). EncryptedSharedPreferences is accepted technical debt per // Open Question #1; the Keystore-backed implementation can replace it // without touching AuthSession. implementation(libs.androidx.security.crypto) implementation(libs.lokksmith.core) implementation(libs.ktor.clientOkhttp) } iosMain.dependencies { // Phase 2 iOS: Darwin engine for Ktor. Lokksmith handles the native // ASWebAuthenticationSession integration directly from Kotlin. implementation(libs.lokksmith.core) implementation(libs.ktor.clientDarwin) } jvmMain.dependencies { implementation(compose.desktop.currentOs) implementation(libs.kotlinx.coroutinesSwing) // Phase 2 Desktop: CIO is the JVM Ktor engine for the dev-mode auth stub // (D-02). The full stub lives in Plan 02-04; this just makes the engine // available so `composeApp:run` still compiles in Phase 2. implementation(libs.ktor.clientCio) } } } dependencies { debugImplementation(libs.compose.uiTooling) } // `group = "dev.ulfrx.recipe"` shifts the Compose Resources `Res` class package from // `recipe.composeapp.generated.resources` to `dev.ulfrx.recipe.composeapp.generated.resources`, // breaking the Phase 1 `App.kt` import. Lock the historical package so module-naming // changes don't cascade into UI code. compose.resources { packageOfResClass = "recipe.composeapp.generated.resources" }