CoinRoutine is a cross-platform cryptocurrency portfolio application built with Kotlin Multiplatform (KMP) and Compose Multiplatform (CMP).
The project demonstrates how to build a production-style mobile application while sharing business logic, data, and UI between Android and iOS. It follows Clean Architecture + MVI, uses dependency injection, local persistence, networking, biometric authentication, and includes both unit tests and Compose UI tests.
🚧 This project is actively being developed and serves as a practical demonstration of modern Kotlin Multiplatform development.
- Browse cryptocurrency information
- View coin details
- Display cryptocurrency market data
- Network-based data fetching
- Image loading for cryptocurrency assets
- Loading and error states
- Create and manage a cryptocurrency portfolio
- Track portfolio holdings
- Calculate portfolio-related values
- Combine portfolio data with current coin information
- Persist portfolio data locally
- Reactive portfolio updates
- Buy cryptocurrency
- Sell cryptocurrency
- Track trade-related information
- Validate trade input
- Update portfolio after trades
The feature/biometric branch introduces biometric authentication to protect the application.
- Android biometric authentication
- Platform-specific biometric implementation
- Authentication state management
- Secure access to protected application content
- Multiplatform architecture using platform-specific implementations where required
The project places a strong emphasis on automated testing.
- Unit tests
- ViewModel tests
- Repository/domain logic tests
- Coroutine testing
- Flow testing with Turbine
- Assertion testing with AssertK
- Compose UI tests
- Android host tests
- iOS simulator tests
- Fake implementations for testing
CoinRoutine follows Clean Architecture combined with the MVI (Model–View–Intent) pattern.
┌─────────────────────────────────────┐
│ Compose UI │
│ Android + iOS (CMP) │
└─────────────────┬───────────────────┘
│
▼
┌─────────────────────────────────────┐
│ Presentation Layer │
│ MVI / ViewModel / State │
└─────────────────┬───────────────────┘
│
▼
┌─────────────────────────────────────┐
│ Domain Layer │
│ Use Cases / Models / Logic │
└─────────────────┬───────────────────┘
│
▼
┌─────────────────────────────────────┐
│ Data Layer │
│ Repository / Remote / Local Storage │
└───────────────┬───────────┬─────────┘
│ │
▼ ▼
Ktor Room
Network Database
MVI provides a predictable unidirectional data flow:
User Action
│
▼
Intent
│
▼
ViewModel
│
▼
Use Case
│
▼
Repository
│
├──────────────► Remote Data
│
└──────────────► Local Database
│
▼
New State
│
▼
Compose UI
This makes state management predictable and makes presentation logic easier to test.
CoinRoutine/
│
├── androidApp/
│ └── Android application entry point
│
├── iosApp/
│ └── iOS application entry point
│
├── shared/
│ ├── src/
│ │ ├── commonMain/
│ │ │ ├── kotlin/
│ │ │ │ └── com/ahmad/raza/coinroutine/
│ │ │ │ │
│ │ │ │ ├── biometric/
│ │ │ │ │
│ │ │ │ ├── coins/
│ │ │ │ │ ├── data/
│ │ │ │ │ ├── domain/
│ │ │ │ │ └── presentation/
│ │ │ │ │
│ │ │ │ ├── portfolio/
│ │ │ │ │ ├── data/
│ │ │ │ │ ├── domain/
│ │ │ │ │ └── presentation/
│ │ │ │ │
│ │ │ │ ├── trade/
│ │ │ │ │ ├── domain/
│ │ │ │ │ └── presentation/
│ │ │ │ │
│ │ │ │ ├── core/
│ │ │ │ ├── di/
│ │ │ │ ├── navigation/
│ │ │ │ └── theme/
│ │ │ │
│ │ │ └── composeResources/
│ │ │
│ │ ├── androidMain/
│ │ ├── iosMain/
│ │ └── commonTest/
│ │
│ └── schemas/
│ └── Room database schemas
│
├── build.gradle.kts
├── settings.gradle.kts
└── gradle/
The repository currently separates coins, portfolio, trade, biometric, core, dependency injection, navigation, and theme functionality inside the shared module.
- Kotlin
- Kotlin Multiplatform
- Kotlin Coroutines
- Kotlinx Serialization
- Kotlinx DateTime
- Compose Multiplatform
- Jetpack Compose
- Material 3
- Compose Resources
- Coil
- Compose UI Testing
- Clean Architecture
- MVI
- ViewModel
- Unidirectional Data Flow
- Repository Pattern
- Use Case Pattern
- Dependency Injection
- Ktor Client
- Kotlinx Serialization
- Platform-specific Ktor engines
- Room for Kotlin Multiplatform
- Bundled SQLite
- Database schema management
- Koin
- Koin Compose
- Koin ViewModel integration
- Android BiometricPrompt
- Multiplatform biometric abstraction
- Platform-specific authentication implementation
- Kotlin Test
- Kotlin Coroutines Test
- Turbine
- AssertK
- Compose UI Test
- Android host tests
- iOS simulator tests
The current shared Gradle configuration includes Compose, Ktor, Room, SQLite, Koin, Coil, biometric support, Kotlin serialization, and the testing libraries listed above.
| Platform | Status |
|---|---|
| Android | ✅ |
| iOS | ✅ |
The shared module currently configures Android plus iosArm64 and iosSimulatorArm64 targets, while the iOS application lives in the dedicated iosApp module.
CoinRoutine uses Kotlin Multiplatform to maximize code sharing between Android and iOS.
Contains code shared between platforms:
- Domain models
- Use cases
- Repositories
- ViewModels
- MVI state
- MVI intents
- Networking abstractions
- Database access
- Compose UI
- Navigation
- Themes
- Business logic
Contains Android-specific implementations such as:
- Android biometric authentication
- Android Ktor engine
- Android-specific integrations
- Android Compose configuration
Contains iOS-specific implementations such as:
- iOS networking engine
- iOS platform integrations
- iOS-specific implementations required by Kotlin/Native
Testing is an important part of CoinRoutine's architecture.
Business and presentation logic can be tested independently from the UI.
Examples include:
ViewModel
↓
Fake Repository
↓
Test Data
↓
Expected MVI State
The project uses:
kotlin.testkotlinx-coroutines-test- Turbine
- AssertK
Compose UI tests verify important user interactions and rendered states.
Examples:
- Verify UI elements are displayed
- Verify text content
- Verify user interactions
- Verify loading states
- Verify error states
- Verify portfolio/trading flows
Run Android shared tests with:
./gradlew :shared:testAndroidHostTestRun iOS simulator tests with:
./gradlew :shared:iosSimulatorArm64TestThese are also the test tasks currently documented by the project.
CoinRoutine uses an API key loaded from local.properties during the build.
Create:
local.properties
and add:
API_KEY=your_api_key_hereThe project uses BuildKonfig to expose the API key to shared Kotlin code without committing the secret into the repository.
⚠️ Never commit your real API key to Git.
- Android Studio
- Kotlin Multiplatform support
- Xcode
- JDK
- Android SDK
- iOS Simulator or physical iOS device
- CocoaPods if required by the selected dependencies
git clone https://github.com/chle0/CoinRoutine.git
cd CoinRoutinegit checkout feature/biometricCreate local.properties:
API_KEY=your_api_key_hereBuild the Android application:
./gradlew :androidApp:assembleDebugThen install/run the generated APK on an Android device or emulator.
Open:
iosApp/
in Xcode and run the application on an iOS Simulator or physical device.
The repository also documents Xcode as the entry point for running the iOS application.
The feature/biometric branch demonstrates adding biometric authentication while keeping the application architecture multiplatform.
The architecture separates the shared authentication contract from platform-specific implementations.
Shared Code
│
Biometric Abstraction
┌─────┴─────┐
│ │
▼ ▼
Android iOS
BiometricPrompt Local Auth
This allows the application to keep its business and presentation logic shared while delegating platform-specific authentication to the appropriate platform APIs.
CoinRoutine was created to demonstrate practical experience with:
- Kotlin Multiplatform
- Compose Multiplatform
- Android + iOS development
- Clean Architecture
- MVI architecture
- Reactive state management
- Ktor networking
- Room Multiplatform
- Koin dependency injection
- Local persistence
- Biometric authentication
- Unit testing
- Coroutine testing
- Flow testing
- Compose UI testing
- Platform-specific implementations
- Shared UI and business logic
This project is more than a cryptocurrency application. It is a practical example of how a modern mobile application can be structured to share a significant amount of code between Android and iOS while still allowing platform-specific functionality when necessary.
The architecture emphasizes:
Shared Code → Clean Boundaries → Predictable State → Testable Logic → Platform-specific Integrations
Potential improvements include:
- More comprehensive UI test coverage
- Additional portfolio analytics
- Advanced cryptocurrency charts
- More robust offline-first behavior
- Improved biometric fallback handling
- CI/CD pipeline
- Code coverage reporting
- Automated release builds
- More comprehensive integration tests
Ahmad Raza
Senior Android Developer | Kotlin Multiplatform | Compose Multiplatform
This project is intended primarily as a demonstration and learning project for modern Kotlin Multiplatform and Compose Multiplatform development.