Kotlin Multiplatform (KMP) Strategy
Relevant source files
The following files were used as context for generating this wiki page:- shared/src/commonMain/kotlin/com/vocabri/shared/Platform.kt
- shared/src/androidMain/kotlin/com/vocabri/shared/Platform.android.kt
- shared/src/iosMain/kotlin/com/vocabri/shared/Platform.ios.kt
- shared/src/commonMain/kotlin/com/vocabri/shared/network/VocabriHttpClientFactory.kt
- gradle/libs.versions.toml
- README.md
The Vocabri project is architected as an offline-first Android application with a forward-looking strategy to support iOS. This is achieved through a dedicated Kotlin Multiplatform (KMP) shared module. This module encapsulates platform-agnostic business logic, networking, and data access, allowing for maximum code reuse between the current Android app and a future iOS app.
The core of the strategy is to isolate platform-independent code in a commonMain source set, while providing platform-specific implementations for Android (androidMain) and iOS (iosMain) where necessary. This approach is evident in the project's structure and its use of KMP-compatible libraries like Ktor for networking and SQLDelight for database persistence.
Sources: README.md:10, README.md:29, README.md:34
KMP Module Structure
The project utilizes a standard KMP module structure with a shared module that contains the common logic. This module is configured to target both Android and iOS.
This diagram shows the shared module at the same level as the app module, with commonMain providing code to both androidMain and iosMain.
Sources: README.md:34
Platform-Specific Implementations (expect/actual)
The KMP strategy heavily relies on Kotlin's expect and actual mechanism to abstract platform-specific APIs. A common interface is defined in commonMain using the expect keyword, and each platform-specific source set (androidMain, iosMain) provides the concrete implementation using the actual keyword.
Example: Platform Class
A clear example is the Platform class, which is designed to provide the name of the underlying platform.
-
commonMain: Defines the expected class and its property.// shared/src/commonMain/kotlin/com/vocabri/shared/Platform.kt expect class Platform() { val name: String }Sources: shared/src/commonMain/kotlin/com/vocabri/shared/Platform.kt:22-24
-
androidMain: Provides the actual implementation for Android, returning the Android SDK version.// shared/src/androidMain/kotlin/com/vocabri/shared/Platform.android.kt actual class Platform actual constructor() { actual val name: String = "Android ${android.os.Build.VERSION.SDK_INT}" }Sources: shared/src/androidMain/kotlin/com/vocabri/shared/Platform.android.kt:24-26
-
iosMain: Provides the actual implementation for iOS, returning the device name and system version.// shared/src/iosMain/kotlin/com/vocabri/shared/Platform.ios.kt actual class Platform actual constructor() { actual val name: String = UIDevice.currentDevice.systemName() + " " + UIDevice.currentDevice.systemVersion }Sources: shared/src/iosMain/kotlin/com/vocabri/shared/Platform.ios.kt:26-28
The relationship between these components can be visualized as follows:
This diagram illustrates that Platform_android and Platform_ios are concrete implementations of the Platform_common expectation.
Shared Networking with Ktor
The shared module includes a platform-agnostic networking layer built with Ktor. A factory, VocabriHttpClientFactory, is defined in commonMain to create and configure an HttpClient.
The factory uses the expect/actual pattern to provide the appropriate Ktor engine for each platform:
- OkHttp for Android
- Darwin for iOS
This is configured through dependencies in the gradle/libs.versions.toml file.
Sources: shared/src/commonMain/kotlin/com/vocabri/shared/network/VocabriHttpClientFactory.kt:23-25, gradle/libs.versions.toml:40-41
VocabriHttpClientFactory
The factory centralizes the HttpClient configuration, including common features like JSON serialization and logging, which are shared across all platforms.
// shared/src/commonMain/kotlin/com/vocabri/shared/network/VocabriHttpClientFactory.kt
object VocabriHttpClientFactory {
fun create(): HttpClient = HttpClient(HttpEngineFactory().createEngine()) {
install(ContentNegotiation) {
json(
Json {
prettyPrint = true
isLenient = true
ignoreUnknownKeys = true
},
)
}
install(Logging) {
logger = Logger.DEFAULT
level = LogLevel.ALL
}
}
}
Sources: shared/src/commonMain/kotlin/com/vocabri/shared/network/VocabriHttpClientFactory.kt:23-41
The HttpEngineFactory is an expect class that resolves to a platform-specific engine factory.
This diagram shows how the common VocabriHttpClientFactory uses a platform-specific HttpEngineFactory to instantiate the correct Ktor engine.
Dependencies and Build Configuration
The KMP strategy is enabled by specific Gradle plugins and dependencies defined in gradle/libs.versions.toml.
| Library/Plugin | Purpose |
|---|---|
plugins.kotlin-multiplatform | The core plugin for enabling Kotlin Multiplatform projects. |
ktor-client-core | The core Ktor client library, used in commonMain. |
ktor-client-okhttp | Ktor engine for Android, used in androidMain. |
ktor-client-darwin | Ktor engine for iOS, used in iosMain. |
sqldelight | KMP-compatible library for type-safe SQL, used for local persistence. |
Sources: gradle/libs.versions.toml:103, gradle/libs.versions.toml:36, gradle/libs.versions.toml:40-41, gradle/libs.versions.toml:106
Conclusion
The KMP strategy in Vocabri establishes a robust foundation for cross-platform development. By placing business logic, networking, and data persistence in a shared module, the project is well-prepared to launch an iOS version with significant code reuse. The use of the expect/actual pattern and KMP-ready libraries like Ktor and SQLDelight demonstrates a clear and effective approach to sharing code while respecting platform-specific capabilities.
Sources: README.md:10, README.md:29