When building a KMP app, keeping shared ViewModels as plain Kotlin classes (composition over inheritance) avoids Android lifecycle dependencies in commonMain. On Android, a wrapper AndroidX ViewModel owns the lifecycle and provides viewModelScope. On iOS, a Swift ObservableObject wrapper bridges Kotlin StateFlows to SwiftUI @Published properties using SKIE async sequences, with explicit cleanup in deinit. This is compared against the official Google-recommended approach of inheriting from androidx.lifecycle.ViewModel in commonMain, which simplifies Android but requires reflection-based bridging on iOS due to Objective-C generics limitations. The pure Kotlin approach trades some boilerplate for explicit lifecycle ownership and easier debugging.
Table of contents
The Strategy: Pure Kotlin ViewModelsAndroid: Lifecycle Ownership via a Wrapper ViewModeliOS: Bridging StateFlow to SwiftUI with an Observer WrapperGet Fredrick Chibuzor Osuala ’s stories in your inboxWhy I Like This ApproachThe Alternative: Lifecycle Multiplatform ViewModelsConclusionSort: