# Stories by Isuru Rajapakse on Medium

Stories by Isuru Rajapakse on Medium

This is one page of public article previews, not the complete archive. Follow Next page to continue. Summaries are not the original full articles.

## Bring your KMP library to NuGet

DevFeed: [Bring your KMP library to NuGet](<https://devfeed.tech/articles/bring-your-kmp-library-to-nuget-25915.md>)

Original publisher: [Read original article](<https://proandroiddev.com/bring-your-kmp-library-to-nuget-02e1131a4707?source=rss-43bae76e8f81------2>)

Author: Isuru Rajapakse

Published: 2026-07-19T13:17:14Z

Content type: tutorial

Language: en

Sources: [Stories by Isuru Rajapakse on Medium](<https://devfeed.tech/sources/stories-by-isuru-rajapakse-on-medium.md>)

Topics: [Kotlin Multiplatform](<https://devfeed.tech/topics/kotlin-multiplatform.md>), [NuGet](<https://devfeed.tech/topics/nuget.md>), [Kotlin](<https://devfeed.tech/topics/kotlin.md>), [C#](<https://devfeed.tech/topics/csharp.md>), [.NET](<https://devfeed.tech/topics/net.md>), [Gradle](<https://devfeed.tech/topics/gradle.md>), [multiplatform](<https://devfeed.tech/topics/multiplatform.md>), [Library](<https://devfeed.tech/topics/library.md>), [API](<https://devfeed.tech/topics/api.md>)

Tags: [android](<https://devfeed.tech/tags/android.md>), [android-app-development](<https://devfeed.tech/tags/android-app-development.md>), [androiddev](<https://devfeed.tech/tags/androiddev.md>), [c-sharp](<https://devfeed.tech/tags/c-sharp.md>), [gradle](<https://devfeed.tech/tags/gradle.md>), [interfaces](<https://devfeed.tech/tags/interfaces.md>), [kmp](<https://devfeed.tech/tags/kmp.md>), [kotlin](<https://devfeed.tech/tags/kotlin.md>), [kotlin-multiplatform](<https://devfeed.tech/tags/kotlin-multiplatform.md>), [library](<https://devfeed.tech/tags/library.md>), [multiplatform](<https://devfeed.tech/tags/multiplatform.md>), [net](<https://devfeed.tech/tags/net.md>), [nuget](<https://devfeed.tech/tags/nuget.md>), [nuget-package](<https://devfeed.tech/tags/nuget-package.md>)

### AI overview

The article introduces kotlin-native-nuget, a Gradle plugin that packages Kotlin/Native libraries as NuGet packages with generated idiomatic C# bindings. It explains the motivation, configuration, publishing workflow, and supported mappings for Kotlin features such as classes, enums, data classes, coroutines, generics, interfaces, and exceptions.

### Source excerpt

with kotlin-native-nuget plugin, you can bring your Kotlin to C# idiomaticallyhttps://medium.com/media/0f185efc67390bbf440bfc33f5675f42/href A little while ago, I gave a talk where I tried to take a library written in Kotlin and hand it to a .NET developer as a NuGet package. By hand. It is 30 minutes of me walking into every brick wall you can imagine - the C ABI, marshalling strings, keeping objects alive across the boundary, making any of it look like C# a human would actually want to use. Introducing kotlin-native-nuget 🪟kotlin-native-nuget plugin auto-binds your kotlin api into C# I turned all of that into a plugin, so you don't have to hit a single one of those walls. You write Kotlin, and out the other side comes a NuGet package with a proper, idiomatic C# API: classes, enums, data classes, coroutines, Flow, generics, interfaces, the works. No FFI boilerplate, no hand-written [DllImport], no "here's a C header, good luck". Your friends over in .NET just `dotnet add package` it and use it like it was C# all along. It's called kotlin-native-nuget, and it's a Gradle plugin. Here's the pitch: GitHub - xxfast/kotlin-native-nuget: A plugin that packages a Kotlin/Native library as a NuGet package with generated C# bindings, and consumes C# NuGet packages from Kotlin The pitch 🛗plugins { kotlin("multiplatform") id("io.github.xxfast.kotlin.native.nuget") version "<version>" } kotlin { mingwX64 { binaries { sharedLib { baseName = "mycatlib" } } } macosArm64 { binaries { sharedLib { baseName = "mycatlib" } } } } nuget { publish { packageId = "MyCatLib" version = "1.0.0" authors = "yourname" description = "My Kotlin/Native library" rootPackage = "com.example.cats" } } That's it. Add the plugin, point it at your native targets, and run the publish task. Out pops a .nupkg. Why though? 🤔 It's a fair question. I got it a lot (even on that talk) Kotlin Multiplatform already reaches an absurd number of places: the JVM, Android, iOS, JS, Wasm, and native desktop. But there's th

## Do-It-Yourself Compose Multiplatform Navigation with Decompose

DevFeed: [Do-It-Yourself Compose Multiplatform Navigation with Decompose](<https://devfeed.tech/articles/do-it-yourself-compose-multiplatform-navigation-with-decompose-25916.md>)

Original publisher: [Read original article](<https://proandroiddev.com/diy-compose-multiplatform-navigation-with-decompose-94ac8126e6b5?source=rss-43bae76e8f81------2>)

Author: Isuru Rajapakse

Published: 2023-02-09T09:02:35Z

Content type: tutorial

Language: en

Sources: [Stories by Isuru Rajapakse on Medium](<https://devfeed.tech/sources/stories-by-isuru-rajapakse-on-medium.md>)

Topics: [compose-multiplatform](<https://devfeed.tech/topics/compose-multiplatform.md>), [navigation](<https://devfeed.tech/topics/navigation.md>), [Android](<https://devfeed.tech/topics/android.md>), [implementation](<https://devfeed.tech/topics/implementation.md>), [Processes](<https://devfeed.tech/topics/processes.md>), [business logic](<https://devfeed.tech/topics/business-logic.md>)

Tags: [android](<https://devfeed.tech/tags/android.md>), [android-app-development](<https://devfeed.tech/tags/android-app-development.md>), [androiddev](<https://devfeed.tech/tags/androiddev.md>), [architecture](<https://devfeed.tech/tags/architecture.md>), [business-logic](<https://devfeed.tech/tags/business-logic.md>), [component](<https://devfeed.tech/tags/component.md>), [compose-multiplatform](<https://devfeed.tech/tags/compose-multiplatform.md>), [implementation](<https://devfeed.tech/tags/implementation.md>), [jetpack-compose](<https://devfeed.tech/tags/jetpack-compose.md>), [multiplatform](<https://devfeed.tech/tags/multiplatform.md>), [navigation](<https://devfeed.tech/tags/navigation.md>), [process](<https://devfeed.tech/tags/process.md>)

### AI overview

A tutorial on building Compose Multiplatform navigation with Decompose for Android and desktop. It explains how to share navigation logic, retain and scope ViewModels, and restore ViewModel state after process death while using a custom architecture.

### Source excerpt

How to survive configuration changes, survive process death and scope ViewModels without going all-in with Decompose 🫢 Decompose recently went 1.0.0 🙌. I think it's a good opportunity to share my specific use case with Decompose where I use it to share navigation logic between Android and Desktop, without going all in with Decompose's Component pattern. Here are some of the problems you would run into - in extracting the navigation to the shared code Abstraction of common navigation. Retaining and scoping your view models Restoring the view models state after the process death. Doesn't Decompose solve all these problems? Why not go all in? This was really just a preference. I wanted to do my own architecture for my app and an inheritance-based component approach wasn't my forte. Luckily Decompose allows you to use parts of it and couple your navigation with business logic (if you want to). Decompose provides you with extensive customisation options to tailor the library to your needs. That's what I ended up doing at the end An Update! 📰 I've decided to publish the implementations of this article as a library called Decompose-Router. This should save you some time if you want to implement this on your own app. If you don't care about the implementation details and just want to use the library, head over there. GitHub - xxfast/Decompose-Router: A Compose-multiplatform navigation library that leverage Decompose to create an API inspired by Conductor The Goal 🥅 This is what we will be working towards. @Parcelize sealed class Screen: Parcelable { object List : Screen() data class Details(val detail: String) : Screen() } @Composable fun ListDetailScreen() { val router: Router<Screen> = rememberRouter(listOf(List)) RoutedContent( router = router, animation = stackAnimation(slide()), ) { screen -> when (screen) { List -> ListScreen(onSelect { detail -> router.push(detail) } ) is Details -> DetailsScreen(screen.detail) } } } @Composable fun ListScreen(onSelect: (detail: Stri

## KStore: A Kotlin Multiplatform Library for Saving and Restoring Objects to Disk

DevFeed: [KStore: A Kotlin Multiplatform Library for Saving and Restoring Objects to Disk](<https://devfeed.tech/articles/kstore-25913.md>)

Original publisher: [Read original article](<https://medium.com/@xxfast/kstore-1be37dd7bc22?source=rss-43bae76e8f81------2>)

Author: Isuru Rajapakse

Published: 2022-10-02T16:01:17Z

Content type: tutorial

Language: en

Sources: [Stories by Isuru Rajapakse on Medium](<https://devfeed.tech/sources/stories-by-isuru-rajapakse-on-medium.md>)

Topics: [Kotlin Multiplatform](<https://devfeed.tech/topics/kotlin-multiplatform.md>), [Library](<https://devfeed.tech/topics/library.md>), [Kotlin](<https://devfeed.tech/topics/kotlin.md>), [Coroutines](<https://devfeed.tech/topics/coroutines.md>), [JSON](<https://devfeed.tech/topics/json.md>), [Testing](<https://devfeed.tech/topics/testing.md>), [CI/CD](<https://devfeed.tech/topics/cicd.md>), [Filesystems](<https://devfeed.tech/topics/filesystems.md>), [GitHub Actions](<https://devfeed.tech/topics/github-actions.md>), [Open Source](<https://devfeed.tech/topics/open-source.md>), [test-coverage](<https://devfeed.tech/topics/test-coverage.md>)

Tags: [ci-cd](<https://devfeed.tech/tags/ci-cd.md>), [code-coverage](<https://devfeed.tech/tags/code-coverage.md>), [coroutines](<https://devfeed.tech/tags/coroutines.md>), [dependencies](<https://devfeed.tech/tags/dependencies.md>), [github-actions](<https://devfeed.tech/tags/github-actions.md>), [kotlin](<https://devfeed.tech/tags/kotlin.md>), [kotlin-multiplatform](<https://devfeed.tech/tags/kotlin-multiplatform.md>), [library](<https://devfeed.tech/tags/library.md>), [open-source](<https://devfeed.tech/tags/open-source.md>), [serialization](<https://devfeed.tech/tags/serialization.md>), [testing](<https://devfeed.tech/tags/testing.md>)

### AI overview

KStore is a small Kotlin Multiplatform library for saving and restoring serialized objects to disk. The article describes its coroutine-based API, storage operations, mutex-protected updates, and project tooling for testing, CI/CD, code coverage, and binary compatibility validation.

### Source excerpt

A tiny Kotlin multiplatform library to save and restore objects to and from the disk So I put out a new library, my first Multiplatform library. KStore is a tiny Kotlin multiplatform library that assists in saving and restoring objects to and from disk using kotlinx.coroutines, kotlinx.serializationand okio Why? A newer version of kotlinx.serialization was released and one thing caught my eye Integration with Okio's BufferedSource and BufferedSink Release 1.4.0-RC - Kotlin/kotlinx.serialization However, there was little to no documentation on how to use it. I scanned through the repository looking for tests but couldn't find any. I asked on slack Got nothing.. But I pulled it down and tried it out anyways. dependencies { implementation("org.jetbrains.kotlinx:kotlinx-serialization-json-okio:1.4.0") } Tried out the most obvious way and wrote up a test case Json.encodeToBufferedSink(value, FILE_SYSTEM.sink(path).buffer()) No luck. Asked around on slack once again Not a minute went by, and our lord and saviour himself descended from heaven to help me out After using use, it worked 🙌. His divinely presence inspired me to write out a bunch more test cases and put this out there in under ~48hrs GitHub - xxfast/KStore: A tiny Kotlin multiplatform library that assists in saving and restoring objects to and from disk using kotlinx.coroutines, kotlinx.serialisation and okio API KStore is inspired by RxStore, and it provides a simple API. Most of these interface methods are suspended, and can only be invoked from a suspended context. SuspendedCreate a storeval store: KStore<Pet> = storeOf("path/to/file")Get valueval mylo: Pet? = store.get() Or observe for changes val pets: Flow<Pet?> = store.updatesSet valuestore.set(mylo)Update a valuestore.update { pet: Pet? -> pet?.copy(age = pet.age + 1) } Note: this maintains a single mutex lock transaction, unlike get() and a subsequent set() Delete/Reset valuestore.delete() You can also reset a value back to its default. store.reset()Sel

## Unconfined Enums Adapter for Moshi

DevFeed: [Unconfined Enums Adapter for Moshi](<https://devfeed.tech/articles/unconfined-enums-adapter-for-moshi-25914.md>)

Original publisher: [Read original article](<https://medium.com/@xxfast/unconfined-enums-adapter-for-moshi-5d84542c8bf0?source=rss-43bae76e8f81------2>)

Author: Isuru Rajapakse

Published: 2022-05-11T12:08:49Z

Content type: tutorial

Language: en

Sources: [Stories by Isuru Rajapakse on Medium](<https://devfeed.tech/sources/stories-by-isuru-rajapakse-on-medium.md>)

Topics: [Kotlin](<https://devfeed.tech/topics/kotlin.md>), [LineageOS](<https://devfeed.tech/topics/lineageos.md>), [API](<https://devfeed.tech/topics/api.md>), [enum](<https://devfeed.tech/topics/enum.md>), [interfaces](<https://devfeed.tech/topics/interfaces.md>)

Tags: [android](<https://devfeed.tech/tags/android.md>), [api](<https://devfeed.tech/tags/api.md>), [data-class](<https://devfeed.tech/tags/data-class.md>), [enum](<https://devfeed.tech/tags/enum.md>), [enum-class](<https://devfeed.tech/tags/enum-class.md>), [how-to](<https://devfeed.tech/tags/how-to.md>), [interfaces](<https://devfeed.tech/tags/interfaces.md>), [kotlin](<https://devfeed.tech/tags/kotlin.md>), [moshi](<https://devfeed.tech/tags/moshi.md>), [retrofit](<https://devfeed.tech/tags/retrofit.md>)

### AI overview

This tutorial presents a Kotlin pattern for handling previously unknown enum-like values from REST APIs with Moshi. It explains Moshi enum adapters, the unknown-value fallback, and an interface-based approach that preserves the server's raw value instead of mapping it only to a generic unknown value.

### Source excerpt

If you wonder what an Unconfined Enum is, wonder no more because it is a thing I just made up. Enums by definition are confined, or finite. Therefore "unconfined enum" is really an oxymoron. Nevertheless, say you have this Fruit enum and want to map each value to an Android string resource. Kotlin's enum properties make this convenient enum class Fruit(@StringRes val stringRes: Int) { Apple(R.string.fruit_apple), Oranges(R.string.fruit_orange) } When we want to consume this enum from a Restful API with a Moshi converter, Moshi automatically generates the enum adapter for you, but if you want to customise the behaviour for whatever reason, you can do object FruitsAdapter { @ToJson fun toJson(type: Fruit): String = type.name @FromJson fun fromJson(name: String): Fruit = Fruit.values().first { it.name == name } } Happy days. Everything is working as expected. When things go bananascom.squareup.moshi.JsonDataException: Expected one of [Apple, Oranges] but was Bananas at path $ Good APIs don't break contracts. Not all APIs are good APIs, so some can break contracts. What do we do now? push out an update with added enum value and its string resource? Perhaps we can make use of EnumJsonAdapter's .withUnknownFallBack() enum class Fruit(@StringRes val stringRes: Int) { Apple(R.string.fruit_apple), Oranges(R.string.fruit_orange), Unknown(R.string.fruit_unknown) } Moshi.Builder() .add(KotlinJsonAdapterFactory()) .add(Fruit::class.java, EnumJsonAdapter.create(Fruit::class.java) .withUnknownFallback(Fruit.Unknown)) .build() This certainly stops the app from crashing, but what if we actually want to show the "bananas" that the API sends? you know, as a fail safe so that users wouldn't end up seeing "unknowns". Let's open up the Enums Enums are by definition finite. Enums are final by design. Enums can't be subclassed but they still can inherit interfaces. We will exploit this to create our "unconfined" enum interface Fruit { val name: String data class Unknown(override val name:

## Going Fully Multiplatform #1: Migrating your Android Project to Kotlin Multiplatform

DevFeed: [Going Fully Multiplatform #1: Migrating your Android Project to Kotlin Multiplatform](<https://devfeed.tech/articles/going-fully-multiplatform-1-migrating-your-android-project-to-kotlin-multiplatform-25912.md>)

Original publisher: [Read original article](<https://medium.com/@xxfast/going-fully-multiplatform-1-migrating-your-android-project-to-kotlin-multiplatform-8fc38763307?source=rss-43bae76e8f81------2>)

Author: Isuru Rajapakse

Published: 2021-10-21T13:24:07Z

Content type: tutorial

Language: en

Sources: [Stories by Isuru Rajapakse on Medium](<https://devfeed.tech/sources/stories-by-isuru-rajapakse-on-medium.md>)

Topics: [Kotlin Multiplatform](<https://devfeed.tech/topics/kotlin-multiplatform.md>), [multiplatform](<https://devfeed.tech/topics/multiplatform.md>), [Kotlin](<https://devfeed.tech/topics/kotlin.md>), [Android](<https://devfeed.tech/topics/android.md>), [iOS](<https://devfeed.tech/topics/ios.md>), [Ktor](<https://devfeed.tech/topics/ktor.md>), [Web](<https://devfeed.tech/topics/web.md>), [Jetpack Compose](<https://devfeed.tech/topics/jetpack-compose.md>), [koin](<https://devfeed.tech/topics/koin.md>), [RxJava](<https://devfeed.tech/topics/rxjava.md>), [navigation](<https://devfeed.tech/topics/navigation.md>)

Tags: [android](<https://devfeed.tech/tags/android.md>), [caching](<https://devfeed.tech/tags/caching.md>), [dependency-injection](<https://devfeed.tech/tags/dependency-injection.md>), [kotlin](<https://devfeed.tech/tags/kotlin.md>), [kotlin-multiplatform](<https://devfeed.tech/tags/kotlin-multiplatform.md>), [ktor](<https://devfeed.tech/tags/ktor.md>), [libraries](<https://devfeed.tech/tags/libraries.md>), [moshi](<https://devfeed.tech/tags/moshi.md>), [multiplatform](<https://devfeed.tech/tags/multiplatform.md>), [navigation](<https://devfeed.tech/tags/navigation.md>), [okhttp](<https://devfeed.tech/tags/okhttp.md>), [retrofit](<https://devfeed.tech/tags/retrofit.md>), [rxjava](<https://devfeed.tech/tags/rxjava.md>)

### AI overview

The article describes migrating an Android-only application to Kotlin Multiplatform. It compares the existing Android stack with a planned multiplatform stack targeting Android, JVM, iOS, and Web, including changes to networking, serialization, caching, dependency injection, asynchronous plumbing, navigation, and UI.

### Source excerpt

Earlier this year I started a mission to start migrating one of our long-lasting Android-only apps to Kotlin Multiplatform to go beyond just Android. This is the story of how that went. Migration from Only-Android to Kotlin Multiplatform!The Android stack This is our current "stack" our android app was set up as follows Targeting Android SDK API 23 or above, we had a few libraries to help us out. The Android-only stack OkHttp for Networking Retrofit for.. also Networking Moshi for serialisation Okio for caching Koin for Dependency Injection/ Service Locator Plumbing with RxJava Navigation with Conductor Imperative UI with Android Views written in XML The Multiplatform stack To go beyond just Android, I had to make some hard decisions to step outside of the comfort zone that we've been so fond of To target Android, JVM, iOS and Web -- we will be making use of The Multiplatform stack Ktor for Networking Kotlin Serialisation for.. serialisation Caching with SQLDelight Koin for Dependency Injection (that one can stay) Plumbing with Coroutine Flows Navigation with Decompose Declarative UI powered with Jetpack/Jetbrains Compose That's the plan! In the next few articles, we'll take a look at each step in more detail. Before jumping on to that -- I want to take a close look at how we can fully modularise a Kotlin Multiplatform project with Going Fully Multiplatform #2 Modularising your Kotlin Multiplatform Project!