Files
recipe/composeApp/build.gradle.kts
ulfrxdev 570652c744 fix(02-07): use kotlinx.coroutines.test.runTest in commonTest for wasmJs
- Add kotlinx-coroutines-test to commonTest dependencies in composeApp
- Refactor AuthSessionTest and LoginViewModelTest from runBlocking to runTest
  so the wasmJs test target compiles (runBlocking is JVM/Native-only)
- App.kt picks up spotless-imposed brace blocks under the auth-gate when
- Log pre-existing SecureAuthStateStoreContractTest and ios SecureAuthStateStore
  ktlint failures to deferred-items.md (out of scope per gsd scope-boundary rule)

Rule 3 (blocking): adding the multiplatform test runtime is needed so
./gradlew check on commonTest sources can compile across all KMP targets.
2026-04-28 17:41:18 +02:00

166 lines
7.1 KiB
Kotlin

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)
// CocoaPods is shipped inside the Kotlin Gradle plugin already on the classpath via
// `recipe.kotlin.multiplatform`. Applying via `alias(libs.plugins.kotlinCocoapods)`
// would request a fresh version and fail with "already on the classpath", so we
// apply it by id only. The catalog still owns the shared Kotlin version.
id("org.jetbrains.kotlin.native.cocoapods")
id("recipe.quality")
}
// Top-level project version is required by the Kotlin CocoaPods plugin when no explicit
// `version` is set inside the `cocoapods { ... }` block. Mirrors `server/build.gradle.kts`
// — Gradle artifact metadata only, NOT a library/plugin pin (per `verify-no-version-literals.sh`).
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"
// AppAuth-Android (D-01) bundles a manifest entry for its
// `RedirectUriReceiverActivity` that requires `${appAuthRedirectScheme}` to be
// resolved at merge time. Pin it to the Phase 2 redirect scheme so simply
// pulling AppAuth into the classpath (Plan 02-01) doesn't break AGP's manifest
// merger before Plan 02-04 lands the full `<intent-filter>` registration.
// Must match `dev.ulfrx.recipe.shared.Constants.OIDC_REDIRECT_URI` byte-for-byte.
manifestPlaceholders["appAuthRedirectScheme"] = "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 {
// The Kotlin CocoaPods plugin (D-01) configures the iOS framework on the iOS targets
// declared by `recipe.kotlin.multiplatform`. `baseName = "ComposeApp"` / `isStatic = true`
// keep existing Swift `import ComposeApp` working. The AppAuth iOS pod version comes
// from the version catalog so this build file stays free of literal pins.
cocoapods {
summary = "Recipe Compose Multiplatform shared framework"
homepage = "https://github.com/ulfrxdev/recipe"
ios.deploymentTarget = "15.0"
podfile = project.file("../iosApp/Podfile")
framework {
baseName = "ComposeApp"
isStatic = true
}
pod("AppAuth") {
version =
libs.versions.appauth.ios
.get()
}
}
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)
implementation(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: AppAuth-Android + AndroidX Security Crypto for the
// SecureAuthStateStore actual (D-01, D-13). EncryptedSharedPreferences is
// accepted technical debt per Open Question #1; the Keystore-backed
// implementation can replace it without touching AuthSession.
implementation(libs.appauth)
implementation(libs.androidx.security.crypto)
implementation(libs.ktor.clientOkhttp)
}
iosMain.dependencies {
// Phase 2 iOS: Darwin engine for Ktor; AppAuth-iOS arrives via the
// CocoaPods block above so the shared framework links it directly.
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)
}
// Adding `group = "dev.ulfrx.recipe"` (required by the Kotlin CocoaPods plugin to render
// the podspec) 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 this plan's wiring
// changes don't cascade into UI code; Plan 02-04+ replaces `App.kt`'s template body anyway.
compose.resources {
packageOfResClass = "recipe.composeapp.generated.resources"
}