| English | Русский |
A native Android admin client for Remnawave — a self-hosted VPN/proxy management panel. Built with Kotlin Multiplatform and Compose Multiplatform, with the entire UI and business logic in shared code (an iOS target compiles as a framework).
https://panel.example.com),# Debug APK
./gradlew :app:assembleDebug
# Release APK
./gradlew :app:assembleRelease
# Unit tests
./gradlew :composeApp:testAndroidHostTest
# iOS framework (requires full Xcode)
./gradlew :composeApp:linkDebugFrameworkIosArm64
Requirements: JDK 17+, Android SDK 36. Minimum Android version: 12 (API 31).
Two-module layout (AGP 9+ forbids com.android.application + kotlin.multiplatform in one module):
| Module | Purpose |
|---|---|
:app |
Thin Android launcher — MainActivity, Application, manifest, resources |
:composeApp |
All shared code: Compose UI, domain, data, DI. Produces an Android AAR and an iOS framework |
Inside :composeApp/commonMain: MVVM with StateFlow, Ktor client with Bearer auth for the Remnawave REST API, repositories mapping DTOs to domain models, Koin for DI, and DataStore for preferences. Navigation is a bottom navigation bar with per-screen master-detail (no navigation-compose). The API key is encrypted at rest via a platform SecretStore (Android Keystore / iOS Keychain).
| Role | Library |
|---|---|
| Language / UI | Kotlin Multiplatform, Compose Multiplatform (Material 3) |
| Networking | Ktor Client + kotlinx.serialization |
| DI | Koin |
| Storage | AndroidX DataStore (multiplatform) |
| ViewModel | JetBrains lifecycle-viewmodel-compose |
| Images / QR | Coil 3, qrose |
| Date/time | kotlinx.datetime |
| Logging | Kermit |
Licensed under the European Union Public Licence v. 1.2 (EUPL-1.2).