r/KotlinMultiplatform

Driviko - My KMP project and experiences

Hey all,

I released Driviko a few weeks ago — a mileage and expense tracker with OBD support — on both the App Store and Google Play.

I wanted to share some of my experience, and also ask for some real-world testing, especially if you use an OBD module with your car. So please don't hesitate to share any thoughts or feedback.

I'm a professional Android developer with ~15 years of experience. I tried a couple of small personal projects on iOS years ago, but that was before ARC and Swift, so my iOS development experience was very limited.

Because of that, most of the gotchas and details below are iOS-focused — mainly because I'm already used to whatever weirdness exists in the Android world.

App targets

Main stack

  • Core: KMP + CMP, MVVM + Clean Architecture
  • Navigation: custom
  • Resources: custom, Kostra (https://github.com/jbruchanov/kostra)
  • Networking: Ktor + Kotlinx Serialization
  • DI: Koin
  • Charts: custom
  • Storage: SQLDelight
  • Maps: Google Maps (Android + iOS), MapKit on iOS, ArcGIS on JVM
  • Analytics: Firebase
  • Crashlytics: Firebase, BugSnag
  • Testing: Junit5+MockK, plus a tiny custom iOS framework to simulate some MockK-like behaviour

In case you're wondering why navigation/resources are not using Compose/KMP solutions — I started the project before there was anything stable or mature enough to use.

Even now, while the official solutions are probably more powerful compared to my own implementations, I still use mine because I have full control over everything and they work well for my use case.

I might migrate in the future, but that's not a priority right now.

Gotchas, lessons learned, and other details

JVM

  • It's mainly a proof of concept for quick UI testing and general debugging.
  • Desktop JVM generally doesn't provide any usable BT stack for Windows/macOS.
  • Any extra/custom gestures need extra care because of mouse/wheel/keyboard differences.

iOS

  • I trapped myself a few times in Kotlin code with incorrect memory management on iOS. Sometimes it's not easy to see the boundary between iOS ARC and Kotlin GC.
  • Working with collections on iOS can be significantly slower compared to JVM/Android. Using fast* collection operators that avoid iterators was basically a must for my stats calculations. Roughly a 10x improvement.
  • Keyboard handling on iOS is, imo, just painful. For example, numeric keyboards don't provide any "Done/Hide" button, so it has to be implemented manually.
  • The Apple dev stack is just a massive pain coming from the Android world. I can't count how many hours I wasted because of Xcode update -> macOS update -> broken local or CI build. Almost every major update breaks something.
  • Unit testing. Most of my tests are regular JVM unit tests mainly because MockK is unbelievably powerful. A few tests are in commonTest covering both platforms. Given how painful iOS debugging is, I tried to cover as much iOS-specific Kotlin code as possible, so I created a very simplistic fake request/response proxy framework to simulate some MockK-like behaviour on iOS. In general, any code depending on iOS APIs is far from easy to test because of static methods and similar platform specifics.
  • Debugging: This is probably the biggest issue in KMP right now for me. Runtime debugging on iOS is basically unusable because of how slow it is. Most custom eval code in LLDB simply doesn't work, so I ended up relying mostly on logs, which is an extremely frustrating time waster.
  • Build times: My CI runner is a 2018 Mac Mini. Android builds usually finish in under 5 minutes, while iOS is often 30+ minutes. Release builds are around 8 minutes on Android and almost 50 minutes on iOS. A better Mac would probably help, but people complain about iOS build speeds in general, so I doubt it would ever get close to Android build times.
  • I hit a stupid iOS bug that caused an infinite loop. Surprisingly, with the debugger attached, force-killing (swiping away) the app somehow completely broke the LLDB bridge, and after that the app just froze forever on startup. The only fix was rebooting the iPhone.
  • Compose gradients on iOS currently don't support dithering, so if you use gradients with subtle color differences, you need to drop down to the Skiko level and implement a custom solution to avoid visible color banding.
  • Firebase Crashlytics could add official support for KMP. Currently, to see nice KMP stacktraces in iOS Crashlytics, manual workaround is needed. BugSnag works just fine. (Shame on you Google!)

Other

  • As a paying IntelliJ IDEA customer, I'm disappointed. It might be better now, but KMP support used to be heavily blocked by AGP incompatibilities with the built-in Android plugin. Also, running Android Studio and IntelliJ IDEA at the same time confused ADB and prevented debugger attachment from either IDE.
  • I'm using GitHub Actions as CI with a self-hosted macOS runner. The whole iOS build process feels disconnected from Gradle. It's basically a mix of Gradle -> xcodebuild -> Gradle. Setting up a proper end-to-end CI release pipeline required a lot of manual work.
  • My main development workstation is running Windows, which generally works fine, but has some annoying gotchas. iOS targets are defined in Gradle, they're completely ignored on Windows, and the IDE happily autocompletes JVM/Android-only APIs inside shared code that later fail on iOS builds. Because of that, running CI for every code change is basically a must. It would be nice if autocomplete behaved contextually based on the target platform of the edited source set.
  • Screen previews are still limited compared to regular Android apps. AGP9 probably improves this somewhat, but I'm not there yet.
  • iOS strangely doesn't seem to have any clean general isPermissionGranted style API. In some cases, simply creating a related object immediately triggers the permission request flow. That makes it difficult to implement soft-ask UX patterns where a permission is only an optional/nice-to-have feature.

The iOS side of KMP still has a lot of room for improvement.

Most of the friction I experienced was around the build/tooling ecosystem, probably because I'm far less experienced with the iOS toolchain. So much of it still revolves around shell scripts and opaque tooling that it often feels stuck in the past.

AI helps much more nowadays, but with things changing rapidly, it's also common to get outdated or completely wrong answers.

The tight coupling between iOS, Xcode, and macOS versions is another constant source of pain. Several times a year it feels like I'm forced into a major update cycle where something inevitably breaks.

Still, after all the work, I'm really happy with the final result.

The app performs well, and I rarely see any UX/performance issues where Compose/KMP could realistically be blamed.

The release/review process was actually smoother on Apple's side compared to Google.

(Though I definitely miss the old days when creating a project and filling all the required forms didn't take an entire day...)

Is it production ready?

I believe so — but be prepared for some hiccups and friction, especially on the iOS side.

And a little bit of boring stats at the end — roughly measured source code by lines just to see how much is stuff is shared/native.

Prod target       %
-------------------
androidMain    5.1%
commonMain    83.2%
iosMain        6.7%
jvmMain        3.4%
jvmShared      0.9%
mobileMain     0.0%
skikoMain      0.3%
swift          0.4%

Tests

Test target          %
----------------------
androidUnitTest   5.9%
commonTest       16.0%
iosTest           7.0%
jvmTest          71.1%
u/Organic-Anxiety-5166 — 14 hours ago
▲ 35 r/KotlinMultiplatform+23 crossposts

I developed Weather World because I wanted a simpler, more helpful way to stay ahead of the forecast. I truly believe that a weather app should be a tool that makes your life easier, not a source of distraction with ads and confusing menus.

How it helps you: The core of the app is all about visual clarity. I’ve focused on creating intuitive graphs that let you see temperature shifts and precipitation trends at a single glance. Instead of reading through long lists of numbers, you can visualize exactly how your day will unfold. It’s minimalist, lightweight, and built for speed—perfect for anyone who values a clean Android experience.

I’d love your support! Please give it a try and see if it helps your daily routine. If you find it useful, please recommend it to your friends! As a solo developer, your support and word-of-mouth are what help me improve and grow.

In compliance with the community rules, I’ve shared the link via IndieAppCircle. Check it out there and let me know what you think!

Find it here: https://play.google.com/store/apps/details?id=com.danie.pocasisveta

u/Tough_Deer_3756 — 1 day ago
▲ 5 r/KotlinMultiplatform+1 crossposts

liquid-glass: iOS 26 frosted glass for Compose Multiplatform with a zero-alloc fallback for low-RAM Android

Hi everyone, sharing a new Compose Multiplatform library I open-sourced today.

liquid-glass adds iOS 26-style frosted backdrop surfaces to CMP. The API is Modifier.liquidGlass() plus three composables: GlassCard, GlassButton, GlassNavBar.

The bit I'm proudest of is the auto-tiered fallback. Three quality tiers picked per platform:

- Full on Android 12+ (non-low-RAM) and iOS 17+: 24dp blur, 1.4x saturation, full-res backdrop.

- Medium on iOS 15 to 16: 16dp blur, 0.5x downsampled backdrop.

- Fallback on Android < 12, isLowRamDevice, or iOS < 15: zero offscreen buffers, no blur, just a flat tint with edge sheen.

Fallback allocates zero GraphicsLayers, so the same code that draws frosted glass on a Pixel 9 quietly draws a flat tint on a 2GB Android 11 device. No OOM, no per-call-site branching.

Targets: Android, iOS (arm64 + simulator), Desktop (JVM), Wasm/JS. Apache 2.0, on Maven Central as 0.1.0.

Quick start:

```kotlin

val state = rememberLiquidGlassState()  // auto-picks tier for the device

Box(Modifier.fillMaxSize()) {

Image(

painter = painterResource(R.drawable.scenery),

contentDescription = null,

contentScale = ContentScale.Crop,

modifier = Modifier.fillMaxSize().liquidGlassSource(state),

)

GlassCard(

state = state,

modifier = Modifier.align(Alignment.Center).padding(24.dp),

) {

Text("Frosted, light-refracting surface")

}

}

```

Credit where it's due: Chris Banes's haze library solves backdrop-blur in Compose really well and is more mature than this. I built liquid-glass because I wanted the tiered fallback baked in by default, not as a thing each consumer has to wire up.

Limitations: 0.1.0. No GlassDialog or GlassBottomSheet wrappers yet, no Sk SL refraction shader, no dynamic-color edge sheen sampled from the backdrop. All on the roadmap.

Repo: https://github.com/NadeemIqbal/liquid-glass

Happy to answer questions about the per-platform auto-detection or the GraphicsLayer sampling approach.

u/DistributionOk9460 — 4 days ago

A New Default Project Structure for Kotlin Multiplatform

Some good news for the end of the work week - we finally have the new default structure ready and shipped! Read the post or watch the video in there for all the details.

IntelliJ IDEA 2026.1.2 was also released today, with support for AGP 9 included.

blog.jetbrains.com
u/zsmb — 5 days ago
▲ 8 r/KotlinMultiplatform+6 crossposts

I really liked KMP, Koog, and the idea of Client-Side MAS. This is the future!

The industry is currently burning billions on server GPUs, and the trend of moving computations to the Edge (end devices) has already started. Apple Intelligence and local NPUs in Android flagships are just the beginning.

Privacy by Design: For projects involving personal data, privacy is critical. Running everything through server cloud systems is a cost of today's technologies, while doing it through local LLMs and MAS is a killer feature. The data does not leave the device!

Native Concurrency: Python suffers from the GIL and workarounds in asynchrony. In KMP, we get native Coroutines and Flow. Agents in Koog are simply lightweight coroutines that communicate via channels without blocking the app's UI thread. This is elegant and mathematically rigorous.

KMP + Koog is the ideal foundation for Client-Side MAS. Python dominates in AI only because of its historically established ecosystem of mathematical libraries. But for orchestrating agents on the device, it is terrible.

But at the moment, we are hostages to the current stage of technological development and popular trends(

reddit.com
u/vladlerkin — 5 days ago
▲ 39 r/KotlinMultiplatform+2 crossposts

Reusable haptic patterns for Android KMP - feedback needed 🙌

Pulsar is a haptics library with more than 150 ready-to-use presets.
https://docs.swmansion.com/pulsar/

It is currently available for Android, but now I’m about to release the Pulsar SDK for KMP 🎉

Do you know any KMP devs who might be interested in trying it out?

I really want to collect some feedback before the official launch - tag them below if anyone comes to mind 🙌

Here is Pulsar-KMP docs: https://docs.swmansion.com/pulsar/sdk/kmp/

u/piaskowyk — 8 days ago
▲ 18 r/KotlinMultiplatform+3 crossposts

I built a local AI coding assistant plugin for IntelliJ IDEA (llama.cpp, no cloud)

I built an AI coding assistant plugin for JetBrains IDEs that runs locally (llama.cpp, no cloud required).

I’ve been using IntelliJ daily and wanted something closer to Cursor/Claude-style workflows, but fully inside JetBrains and without sending code externally.

So I ended up building this.

It integrates directly into the IDE and supports:
– project-aware chat (understands your codebase)
– AI agent for applying code changes
– multi-file edits with diff previews
– external docs/web research with citations
– MCP server/tool support
– background code health analysis

Everything can run locally depending on your setup, so it’s privacy-friendly and works offline.

I’m actively improving it and would really appreciate feedback from other JetBrains users — especially around UX and how it fits into your workflow.

Plugin page: https://plugins.jetbrains.com/plugin/31304-llamatik-code/

u/ferranpons — 8 days ago
▲ 0 r/KotlinMultiplatform+1 crossposts

عاوز اتعلم KMP

كنت بتعلم في البدايه تراك .net maui ومتعلم c# and web api وكل مشتملاته ولكن كان عندي امل ان ماي تتحسن الي وقتنا هذا مفيش تطور ف انا بفكر اغير ل كوتلين للاندرويد و ios وسمعت انه فيه ل ويندوز ف انا مش عارف ابدأ ازاي واي الرود ماب واي مقارنتها ب فلاتر " انا مش بحب فلاتر " و عاوز اعرف قنوات شامله الرودماب من البدايه للنهايه من اساسيات كوتلين ل اني اعمل برنامج بال view model و ال advanced

reddit.com
u/ImpossibleGround6528 — 8 days ago
▲ 13 r/KotlinMultiplatform+3 crossposts

I released SQLiteNow for Flutter/Dart: SQL-first, type-safe SQLite codegen

Hey Flutter folks,

I just published the first Dart/Flutter release of SQLiteNow. If you used SQLDelight before with Kotlin Multiplatform - you would feel right at home.

Short version: SQLiteNow lets you keep your database schema and queries as normal .sql files, then generates typed Dart code around them: params, result models, migrations, transactions, query namespaces, and reactive watch() APIs.

It is not trying to hide SQLite behind a big ORM. The idea is closer to: write real SQL, keep full control over the database, but stop manually mapping rows and passing dynamic parameter maps everywhere. No plugins needed, you write your code in any editor that supports .sql files, you just use your knowledge of SQL and SQLite. Additionally there are annotations available as comments --@@{...} to shape and control data generated.

The part I personally care about is that SQLiteNow is not trying to make SQLite disappear. You still write normal SQLite:

  -- @@{ queryResult=TaskWithTags }
  SELECT
    t.id,
    t.title,
    t.completed,

    tag.id AS tag__id,
    tag.name AS tag__name

  /* @@{ dynamicField=tags,
         mappingType=collection,
         propertyType=List&lt;TaskTag&gt;,
         sourceTable=tag,
         collectionKey=tag__id } */
  FROM task t 
  LEFT JOIN task_tag tt ON tt.task_id = t.id
  LEFT JOIN tag ON tag.id = tt.tag_id
  ORDER BY t.id, tag.name;

and SQLiteNow generates the Dart result type and query method around it. So instead of hand-reading rows, building maps, or doing a second pass to group tags under tasks, you get a typed result shaped like your app actually wants:

  final tasks = await db.task.selectWithTags().asList();
  for (final task in tasks) {
    print('${task.title}: ${task.tags.map((t) =&gt; t.name).join(', ')}');
  }

That is the main difference from using sqlite3/sqflite directly: I still get real SQL, but not all the manual row mapping.

And yes, when you use a watch() - any changes to `task` or `tag` tables will reactively update your data.

Compared with higher-level database libraries, the design goal is a bit different too. SQLiteNow is very SQLite-specific and SQL-file-first. Schema, migrations, seed data, and queries live as SQL assets, and annotations are just SQL comments. I wanted the generated code to stay close to my domain model without moving the real database logic into a Dart DSL or ORM layer.

A bit of context: SQLiteNow originally started as a Kotlin Multiplatform project and KMP version is used in production by quite a few of people. And now Dart/Flutter packages are published on pub.dev.

There is also an optional sqlitenow_oversqlite package for sync/multi-device work, but you can ignore that completely if you only want local SQLite.

Current honest status:

- first public Dart/Flutter release, 0.9.0

- targets Dart VM and Flutter native runtimes through package:sqlite3

- web support is not public yet

- docs may still show some KMP history, but the Flutter path is there now

Links:

- GitHub: https://github.com/mobiletoly/sqlitenow-kmp

- Flutter docs: https://mobiletoly.github.io/sqlitenow-kmp/flutter/

- Runtime: https://pub.dev/packages/sqlitenow_runtime

- CLI: https://pub.dev/packages/sqlitenow_cli

- Optional sync runtime: https://pub.dev/packages/sqlitenow_oversqlite

I'd really appreciate feedback from people who build SQLite-heavy Flutter apps. Especially if you've used drift, sqflite, or handwritten sqlite3 code and have opinions about where this approach feels useful or annoying.

u/Adventurous-Action66 — 8 days ago

Llamatik - Kotlin Multiplatform library for local AI (LLMs, speech, images) on Android, iOS, JVM &amp; WASM

Hi all,

I’ve been working on Llamatik, an open source Kotlin Multiplatform library that brings local AI models (LLMs, speech, and image generation) to multiple platforms using a shared API.

### 🌍 Supported platforms
- Android
- iOS (arm64 + simulator)
- JVM (desktop/server)
- Web (WASM, experimental)

### 🧠 What it supports
- llama.cpp → local LLM inference
- whisper.cpp → speech-to-text
- stable-diffusion.cpp → image generation

### 🔧 What it does
- Provides a Kotlin-first multiplatform API
- Runs models fully on-device / offline
- Lets you share AI logic across mobile, desktop, and web

### 💡 Why I built it
Most local AI tooling is:
- Python-first
- Hard to integrate into mobile apps
- Not designed for shared codebases

I wanted something that:
- Works in real apps (Android + iOS + Desktop + Web)
- Feels natural for Kotlin developers
- Doesn’t require a backend

### ⚙️ Technical highlights
- Kotlin Multiplatform + C++ interop
- Integration with llama.cpp, whisper.cpp, stable-diffusion.cpp
- CMake + Gradle build pipeline
- Static linking for iOS
- Early WASM support

### 📦 Current status
- Core functionality working across platforms
- API and DX still evolving
- Some rough edges in native builds

### 🙌 Looking for
- Feedback on API design
- Ideas for real-world use cases

### 🔗 Repo
https://github.com/ferranpons/Llamatik

Curious to hear how people would use local AI like this in real apps.

github.com
u/ferranpons — 8 days ago

Debugging iOS KMP

Hi fellow devs,

I'm wondering, how do you debug KMP code on iOS ?
I find it extremely painful.
Currently I'm using android studio,
but just regular debug workflow is mentally slow,
any basic variables preview in "eval window/terminal" doesn't work.

So it's sort of try&log approach which feels like going 50years back...

Am I missing something here ?
I've tried xcode but that has own limits as well, and xcode on its own is just painful to use comparing to android studio.

reddit.com
u/Organic-Anxiety-5166 — 9 days ago
▲ 15 r/KotlinMultiplatform+1 crossposts

Kotlin likes to pretend primitives (int/long/float/double) don't exist (and generally does a reasonable job of this), but it falls apart a bit when it comes to collections. It's always bothered me how inefficient standard collections are in wasting both memory and CPU when it comes to storing primitives so I took matters into my own hands and wrote a high performance primitive collections library for KMP. High level languages should not have to imply bad performance.

I had a couple main goals for the FastCollect library:

  1. Maintaining compatibility with existing standard library collections and interfaces (List/Map/Set we all know and love) so that this could function as a drop in replacement for the most part.
  2. Substantially better performance than standard library collections, and performance on par with or better than existing high-performance JVM libraries (fastutil and Eclipse).
  3. Creating a reasonable default for high-performance primitive collections for multi-platform, not just JVM.
  4. Investigating Robin Hood hashing in some detail, which I've always been interested in.

I think I've largely succeeded here - benchmarking shows a ~4-5x reduction in memory usage and ~2-4x improvement in CPU usage (up to 10x in some specific benchmarks) when replacing standard library collections! In particular I made a point of having high memory efficiency for empty/small collections, which is an area many libraries neglect in spite of the fact that real world programs tend to have many empty/small collections. There is no other library for multi-platform Kotlin that supports reasonable primitive collection performance I'm aware of. A benchmark teaser:

List Iteration

Library / Size 3,000 12,000 48,000 192,000 768,000 3,072,000
fastcollect 0.294 us 1.186 us 4.496 us 17.972 us 66.602 us 272.948 us
kotlin 0.604 us 2.325 us 9.891 us 45.308 us 156.577 us 1266.579 us

If you want to try it yourself, stick in implementation("io.github.sooniln:fastcollect-kotlin:1.0.0") and you're good to go.

Performance thoughts

Performance is also competitive with JVM primitive libraries like fastutil and Eclipse - they generally have a small edge, but not by much. Unsurprising given they've been optimized for years thus far. Since these are Java-centric libraries however, their APIs are often really annoying to use from Kotlin, and they don't support many standard Kotlin idioms for interacting with collections (and of course only run on JVM).

In particular I was impressed with Eclipse's cuckoo hashing implementation and wanted to talk about that for a moment - I've generally poo-poo'd the coo-coo as being overly complex for little benefit compared to other hashing strategies, but it really shines for primitives. Primitive hashcodes have excellent (low) collision probabilities over the full 32 bits, and perfect uniformity, but extremely poor entropy (especially over the subset of bits hashtables care about). This means implementations generally need to 'smear' hashcodes to create and spread the entropy over the bits relevant to the hashtable. Smearing algorithms are also often the most important factor in hashtable performance, so finding algorithms that are fast but also do a good job smearing is essential. Without smearing hashtable performance deteriorates dramatically on adversarial inputs (for example I measured a 200x decrease in performance of a naive smearing algorithm when faced with high-bit inputs) - but because cuckoo hashing uses two hash functions it can choose both a fast smear and a more expensive fallback smear to try and get the benefit of both worlds. Eclipse had excellent results from this approach in my benchmarking. I may investigate cuckoo hashing myself in the future, especially as I'm curious how it handles more adversarial inputs rather than just the random data I benchmarked with. I also dumped some of my development thoughts while writing my hashtable.

Anyways, please let me know if this library would be useful to you, or if there are features/collections you'd want that would be useful!

u/tooilln — 14 days ago