Architecture
How SimpMusic is built — Kotlin Multiplatform, Clean Architecture, MVVM, and the FOSS/Full split.
SimpMusic is a Kotlin Multiplatform (KMP) app built with Compose Multiplatform, sharing UI and logic across Android and Desktop (JVM).
iOS targets are declared in many modules, but the iOS app is not shipped yet.
Clean Architecture
The codebase is organized into three layers, enforced by the direction of module dependencies:
- Domain — platform-agnostic models and contracts (entities, manager interfaces). Depends
only on the
commonmodule; no framework code. - Data — repository implementations, the Room database, DataStore, parsers and Koin DI
modules. Depends on
domain+commonand aggregates the service modules. - Presentation (
composeApp) — Compose Multiplatform screens with MVVM ViewModels. Depends ondomain/commonand ondata.
The two app modules — androidApp and desktopApp — are thin shells over composeApp.
MVVM
ViewModels live in composeApp/.../viewModel and are provided through Koin
(koin-compose-viewmodel); Compose screens observe them via lifecycle-aware state.
Kotlin Multiplatform source sets
commonMainholds the bulk of the shared logic and UI.expect/actualbridges platform differences — the clearest example isMusicDatabase(common declaration +.android.kt/.jvm.kt/.ios.ktactuals).- Platform engines differ by target: OkHttp (Android/JVM) vs Darwin (iOS) for the Ktor client; Media3/ExoPlayer on Android vs VLC on Desktop for playback.
Tech stack at a glance
| Concern | Choice |
|---|---|
| Language / build | Kotlin 2.4, KSP, AGP 9 |
| UI | Compose Multiplatform 1.11 + Material 3 |
| Dependency injection | Koin |
| Networking | Ktor (OkHttp / Darwin engines) |
| Database | Room (KMP) + DataStore |
| Images | Coil |
| Playback | Media3/ExoPlayer (Android), VLC/VLCJ (Desktop) |
| Lyrics / AI | LRCLIB & others; Gemini / OpenAI |
| Crash reporting | Sentry (Full build only) |
FOSS vs Full
The FOSS/Full distinction is not an Android product flavor — it's driven by the Gradle
property isFullBuild. It gates two module pairs, each a real implementation plus a
no-op twin exposing the same API:
| Capability | Full build | FOSS build |
|---|---|---|
| Crash reporting | :crashlytics (Sentry) | :crashlytics-empty |
| Google Cast | :cast (Cast SDK) | :cast-empty |
Both stubs exist for F-Droid compliance — the FOSS build links no proprietary SDK, which means casting is unavailable in FOSS builds.
