KRelay: The Native Interop Bridge for Kotlin Multiplatform
KMP isn't just about sharing code; it's about managing Native UI safely. KRelay is the tool that makes it possible.
In my 15 years of mobile engineering — from J2ME to Flutter and now Kotlin Multiplatform (KMP) — one "final boss" always remains: Native Interop. How do you trigger native UI components like Toasts, Camera, or Navigation from shared code without causing memory leaks, threading crashes, or losing events during screen rotation?
Enter KRelay — a library designed with the Unix Philosophy: "Do one thing and do it well."
The Core Value: Why KRelay?
Traditionally, calling platform-specific code from shared ViewModels requires complex patterns:
-
Boilerplate Overload: You often need
MutableSharedFlow+emit+collectAsState+LaunchedEffectjust for a simple notification. -
Memory Leaks: Strong references to an Activity or ViewController in shared code prevent garbage collection, leading to
OutOfMemoryError. - Event Loss: If you dispatch a command while the UI is recreating (e.g., during rotation), that event is often lost forever.
KRelay solves these issues through three fundamental pillars:
1. Weak Registry
KRelay automatically manages WeakReferences to your platform implementations. When a ViewController or Activity is destroyed, the reference is cleared automatically.
2. Sticky Queue
If your ViewModel dispatches an action while the UI is not ready (e.g., during a cold start or rotation), KRelay queues the action and replays it as soon as the UI registers.
3. Safe Dispatch
All commands are automatically executed on the platform's Main/UI thread (using Looper on Android and GCD on iOS), preventing threading-related crashes.
The "Ultimate Combo": KRelay + Adapter Pattern
One of the biggest hurdles in 2026 is that many modern Swift libraries (like Lottie or Alamofire) are "Pure Swift" and are not visible to Kotlin's cinterop.
The Adapter Pattern combined with KRelay is the most powerful solution:
-
The Strategy: Define an interface in
commonMain(e.g.,NavFeature). Create a Swift Adapter that implements this interface and calls your 3rd-party Swift library. - The Benefit: Your ViewModel stays pure and testable. KRelay acts as the safe messenger, handling the threading and lifecycle complexities of the native implementation.
Technical Deep-Dive
KRelay is a high-performance Runtime bridge, avoiding the complexity and build-time overhead of KSP or reflection.
Installation
Add the library to your shared module's dependencies:
// shared/build.gradle.kts
commonMain.dependencies {
implementation("dev.brewkits:krelay:1.0.0")
}
Core API Usage
Defining and using a feature is straightforward:
// 1. Define (commonMain)
interface ToastFeature : RelayFeature {
fun show(message: String)
}
// 2. Dispatch (Shared Logic)
KRelay.dispatch<ToastFeature> { it.show("Hello!") }
// 3. Register (Android/iOS Native)
KRelay.register<ToastFeature>(AndroidToastImpl(context))
Advanced Features
-
Priority System: Use
ActionPriority(LOW to CRITICAL) to ensure important events like error dialogs are replayed first. - Performance Metrics: Monitor dispatch counts and queue statistics per feature to optimize your app.
-
Safe Clean-up: Use
clearQueue<T>()in your ViewModel'sonCleared()to prevent lambda capture leaks.
Project Architecture
KRelay's internal structure is optimized for platform-specific efficiency:
KRelay/
├── commonMain/ # Core registry and queue logic
│ └── KRelay.kt, Priority.kt, Metrics.kt
├── androidMain/ # Android Looper and ReentrantLock
│ └── Lock.android.kt, MainThreadExecutor.android.kt
└── iosMain/ # iOS GCD and NSRecursiveLock
└── Lock.ios.kt, MainThreadExecutor.ios.kt, KRelay+Extensions.swift
Important Limitations
- Process Death: KRelay's queue is in-memory and does not survive process death. Never use it for critical transactions like payments.
- Singleton Scope: While simple for most apps, large Super Apps should use Feature Namespacing to avoid registry conflicts.
Verdict
KRelay isn't trying to be a state manager or a background worker. It is a focused, reliable messenger for one-way UI commands. By combining KRelay with the Adapter Pattern, you gain the flexibility to use any native library while maintaining the cleanest shared code architecture possible.
Start building safer KMP apps today.
GitHub Repository: github.com/brewkits/krelay
Tags: #KotlinMultiplatform #KMP #NativeInterop #AndroidDev #iOSDev #CleanArchitecture
Top comments (0)