Kotlin Multiplatform v praxi: jak sdílet kód mezi iOS a Androidem (a čemu se vyhnout)

📺 Záznam přednášky Rostislava Babáčka z Ackee Meets: Mobile Development:
Kotlin Multiplatform (KMP) slibuje něco jako svatý grál mobilního vývoje: napsat business logiku jednou a používat ji nativně na iOSu i Androidu. Zní to skvěle – a ono to skvělé opravdu být může. Cesta k tomu ale vede přes pár nečekaných crashů, jeden dva večery strávené hádkou s Gradlem a moment, kdy si iOSák poprvé otevře Android Studio a chvíli neví, kam vůbec klikat. My v Ackee jsme si tím prošli, když jsme spojili do té doby oddělené iOS a Android týmy nad jedním sdíleným kódem. Tady je upřímný přehled úskalí i toho, co reálně funguje.
📋 TL;DR
- Kotlin Multiplatform (KMP) umožňuje sdílet business logiku, síťovou vrstvu a práci s daty mezi iOSem a Androidem, zatímco UI zůstává nativní.
- „Stačí to jen napojit“ je mylná představa. Platformy se nechovají stejně, Kotlin má schované runtime pasti (
first()vs.firstOrNull(), chybějící@Throws) a export do Swiftu není zadarmo. - Klíč není v technologii, ale v lidech a procesech: cílené workshopy, čas na vzdělávání, monorepo a společné analýzy obou platforem.
- Osvědčené nástroje: SKIE (Swift-friendly API generátor od TouchLabu), Koin (DI), Detekt (statická analýza), Kotlin Native Xcode Plugin (debugging) a git worktree proti zbytečným buildům.
- Přínos dobře nasazeného KMP: až ~30 % úspora času u featur se sdílenými ViewModely, sjednocené chování aplikací a vyšší zastupitelnost vývojářů.

🧩 Co je Kotlin Multiplatform (KMP)?
Kotlin Multiplatform je technologie od JetBrains, která umožňuje sdílet část kódu mezi platformami – typicky business logiku, síťovou vrstvu nebo práci s daty – a přitom si na každé platformě ponechat nativní UI. Sdílený kód se píše v Kotlinu a na iOS se exportuje jako framework, který se pak volá ze Swiftu.
Právě kombinace „sdílená logika + nativní vzhled“ je hlavní výhoda KMP oproti řešením jako Flutter nebo React Native, kde se sdílí i UI. Kotlin Multiplatform Mobile šel do alfy už v roce 2020, stabilní verze dorazila v roce 2023 – a od té doby je z KMP nástroj, který dává smysl nasazovat i na produkčních klientských projektech.

⚖️ Kdy KMP dává smysl (a proč ne Flutter nebo React Native)
KMP se vyplatí tam, kde chcete jednotnou business logiku napříč platformami, ale nechcete slevit z nativního UI a výkonu. Sdílíte to, co má být na obou platformách stejné (logika, validace, práce s daty), a necháváte nativní to, co platformně specifické být má (vzhled, animace, systémové integrace).
Proto bývá KMP volbou i tam, kde by čistě „jedna codebase pro všechno“ nevyhovovala: nesdílíte UI vrstvu, takže se nevzdáváte nativního look & feel ani přístupu k platformním API. Bonus, na který se často zapomíná: s nativním UI zůstává nativní i přístupnost, kterou VoiceOver a TalkBack umí bez obcházení.
Tady je KMP v přímém srovnání s Flutterem a React Native:
| Vlastnost | Kotlin Multiplatform | Flutter | React Native |
|---|---|---|---|
| Co se sdílí | business logika (UI zůstává nativní) | logika i UI | logika i UI |
| UI vrstva | plně nativní (SwiftUI / Jetpack Compose) | vlastní vykreslování (Skia) | most do nativních komponent |
| Nativní vzhled a výkon | zachovaný | blízko nativu, ale vlastní render | dobrý, s režií mostu |
| Přístup k platformním API | přímý a nativní | přes pluginy | přes pluginy a mosty |
Do téhle mapy mezitím vstoupil ještě jeden hráč, a to z opačného směru: Swift SDK for Android, které zkouší dostat Swift na Android. Zatím spíš experiment než produkční volba, ale směr stojí za sledování.
🚧 Nejčastější úskalí při zavádění KMP
Přechod z „píšu jen jednu platformu“ na „píšu i sdílený Kotlin“ má několik opakujících se úskalí. Tahle patří k nejčastějším.
Platformy se nechovají stejně
Sdílená logika neznamená, že se obě platformy chovají identicky. Krásný příklad je předávání dat přes navigaci: Android má limit na velikost dat posílaných přes navigaci, zatímco iOS ne. Řešení, které v pohodě funguje na iOSu (poslat objekt přímo), tak na Androidu spadne a je nutné data ukládat jinam (třeba do databáze) a přes navigaci posílat jen ID.
Pro tyhle případy je zásadní znát mechanismus expect/actual, který umožňuje mít ve sdíleném kódu společné rozhraní a platformně specifickou implementaci. Bez něj snadno naimplementujete „androidí“ workaround i na iOSu, kde ho vůbec nepotřebujete.
Rozdílná architektura: MVVM vs. Clean Architecture
iOS aplikace často stojí na MVVM (případně TCA), které řeší hlavně vztah View a ViewModelu. Android svět naopak běžně jede na Clean Architecture, a ta se přirozeně propíše i do sdíleného KMP kódu. Clean Architecture je výrazně striktnější na hranice mezi vrstvami – najednou zjistíte, že volat z jedné repozitory rovnou jinou není validní, o čemž vám MVVM nikdy neřeklo ani popel. Sladit architektonické zvyklosti obou platforem je jeden z prvních úkolů, který je potřeba vyřešit.
Skryté runtime pasti v Kotlinu
„Kotlin vypadá jako Swift, tohle dám levou zadní.“ Spoiler: nedáte. Kotlin má pasti, které kompilátor při přechodu neodhalí a projeví se až za běhu pěkným runtime crashem. Dvě nejčastější:
1. Chování first() na kolekci. Ve Swiftu vrací first optional. V Kotlinu first() na prázdné kolekci vyhodí NoSuchElementException:
list.first() // ⚠️ NoSuchElementException, když je kolekce prázdná
list.firstOrNull() // ✅ bezpečná varianta – vrací null2. Neošetřené výjimky přes hranici do Swiftu. Ve Swiftu ze signatury poznáte, že funkce vyhazuje chybu, a kompilátor vás donutí ji ošetřit. V Kotlinu ne. Pokud u rozhraní, které může vyhodit výjimku, chybí anotace @Throws, swiftová strana o té výjimce vůbec neví – a je z toho crash:
public interface SetupHeartbeatObserverUseCase {
@Throws(Throwable::class) // ✅ bez této anotace Swift neví, že může přijít výjimka
public suspend operator fun invoke()
}Integrace a export do Swiftu
Po exportu z KMP nejsou vygenerovaná API přirozeně swiftová. Když potřebujete něco mockovat nebo pěkně integrovat, píšete kolem toho hromadu wrapperů a mapperů – a bez správně navržené architektury se z integrace stane menší očistec.
Vývojové prostředí a build frameworku
iOS vývojář zvyklý na Xcode narazí na neznámé Android Studio, jiné klávesové zkratky a na Gradle s desítkami tasků (a chvíli netuší, kde vůbec začít). Největší praktická brzda je ale build frameworku: při každé změně ve sdíleném KMP kódu je potřeba framework znovu sestavit – a to je čas, který byste radši věnovali čemukoli užitečnějšímu.

🛠️ Jak úskalí překonat
Sladit dvě platformy nad jedním kódem není jen otázka nástrojů, ale hlavně lidí a procesů. Nám se osvědčilo pět věcí:
- Cílené workshopy – zkušenější platforma vede workshopy mířené na konkrétní projekty, ne na obecné koncepty. Vývojář si pak snadno najde paralelu se světem, který zná.
- Vyhrazený čas na vzdělávání – přechod na novou technologii chce prostor. V Ackee máme na vzdělávání 10 % pracovní doby, což lidem dává reálnou možnost se v KMP a Kotlinu zlepšit.
- Monorepo – dokud je sdílený kód jen submodul, tým ho bere jako externí knihovnu, která ho „nezajímá“. V monorepu má přehled o tom, co se ve sdílené vrstvě děje.
- Společné analýzy – u návrhu integrace mějte vždy zástupce iOSu i Androidu. Cílem je kompromis, ne aby jedna platforma diktovala řešení, které se druhé bude integrovat přes slzy.
- Přijetí reality – s tím, že to zpočátku bude trvat déle, musí počítat tým i projektové vedení. Návratnost přijde s časem.
„Feature, kterou bych nativně napsal za dvě hodiny, mi v KMP na začátku klidně zabere šest. Ale je potřeba se do toho opřít – a časem se to zásadně zlepší.“
Nástroje, které přechod usnadní
- SKIE (od TouchLabu) – generátor Swift-friendly API nad KMP. Umožní ze Swiftu pohodlně sledovat stav KMP ViewModelu bez ručně psaných wrapperů.
- Koin – dependency injection pro sdílený kód.
- Detekt – statická analýza, kterou lze pokrýt řadu runtime pastí (třeba vynutit
@Throws). Deterministické linty odhalí chybu dřív, než se z ní stane crash v produkci. - Kotlin Native Xcode Plugin (od TouchLabu) – dá vám breakpointy přímo do KMP kódu a náhled na stack trace i hodnoty proměnných místo dokola přidávaných printů a rebuildů.
- git worktree – vedlejší klon repozitáře pro rychlé hašení incidentů; framework sestavíte jednou a při návratu na původní větev vám odpadá další build.
Čím víc logiky (včetně ViewModelů) přesunete do sdíleného kódu, tím míň jí zbyde na platformě – chování se sjednotí a opravy děláte na jednom místě, ne na dvou. Se SKIE k tomu navíc odpadají ruční wrappery kolem KMP ViewModelů.
🤖 Agentic development v KMP monorepu
Monorepo se sdíleným kódem se dobře snáší s AI-asistovaným vývojem. Osvědčují se:
- Scoped rules – agent si do kontextu nenačítá pravidla pro Android/KMP, když se pracuje jen na iOS části (a naopak).
- Skills na opakující se integrační úkoly (přidání KMP modulu, integrace ViewModelu na platformě).
- Review agent na runtime chyby – jako doplněk, ne náhrada deterministických lintů.
Orchestrace více agentů je zatím diskutabilní – ještě se úplně neví, jestli agentovi pomáhá, nebo ho spíš mate.
👥 Organizační dopad: z platformních týmů projektové
Sdílení kódu má i organizační přesah. Když iOS i Android vývojáři pracují nad stejnou logikou, přestává dávat smysl dělit týmy podle platformy. V Ackee jsme proto přešli z oddělených iOS a Android týmů na mobilní týmy zaměřené na projekty: každý tým je mix obou platforem, sdílí know-how a kontext k projektům a platformní světy se postupně sbližují. Nad tím pomáhá pravidelný společný all-hands s technologickými novinkami.
Výsledkem je vyšší zastupitelnost: přijde incident a vyřešit ho může kterýkoli mobilní vývojář, ne jen „ten od dané platformy“.

📈 Jaké to má výsledky
Dobře nasazený KMP přináší měřitelné i „měkké“ benefity:
- Až ~30 % úspora času (interní odhad z našich projektů, ne měření) u featur, kde je logika (včetně ViewModelů) ve sdíleném kódu.
- Sjednocené chování aplikací – obě platformy se chovají stejně, což ocení QA i klient.
- Vyšší zastupitelnost vývojářů a méně duplicitní logiky, kterou by jinak bylo nutné opravovat na dvou místech.
Úspora není univerzální. U některých featur neušetříte nic, jinde jde o jednotky procent – a dokud logika (třeba ViewModely) není ve sdíleném kódu, může být přínos nulový i záporný. Rozdíl dělá dobrý návrh a poctivá analýza.
❓ FAQ
Co je Kotlin Multiplatform (KMP)?
Technologie od JetBrains pro sdílení kódu (business logiky, síťové vrstvy, práce s daty) mezi iOSem a Androidem, při zachování nativního UI na každé platformě.
Jaký je rozdíl mezi KMP a Flutterem nebo React Native?
KMP sdílí jen business logiku, UI zůstává nativní. Flutter a React Native sdílejí i UI vrstvu. KMP proto volí týmy, které nechtějí slevit z nativního vzhledu a výkonu.
Proč aplikace v KMP crashuje na first()?
Kotlinovská first() na prázdné kolekci vyhazuje NoSuchElementException. Používejte firstOrNull(), která vrací null.
K čemu je anotace @Throws v KMP?
Bez ní swiftová strana neví, že sdílená funkce může vyhodit výjimku, a přijde runtime crash. @Throws výjimku „zviditelní“ pro interoperabilitu se Swiftem.
Kolik času KMP reálně ušetří?
U featur se sdílenými ViewModely v praxi až ~30 %. Úspora ale závisí na návrhu; u některých featur je minimální nebo žádná.
Jaké nástroje se pro KMP vyplatí?
SKIE (Swift-friendly API generátor), Koin (DI), Detekt (statická analýza), Kotlin Native Xcode Plugin (debugging) a git worktree (rychlejší práce s buildy).
🎯 Co si odnést
Sdílení kódu mezi iOSem a Androidem přes Kotlin Multiplatform není jen technické „napojení“. Je to změna technologická i organizační, která stojí na ochotě obou platforem sladit architekturu, poctivě analyzovat a smířit se s tím, že návratnost přijde postupně. Když to ustojíte, výsledkem jsou konzistentní aplikace, zastupitelní vývojáři a mobilní tým, který táhne za jeden provaz – i když se u prvních crashů zapotíte.
Celý příběh i s diskuzí z publika najdete v záznamu přednášky. Termíny dalších Ackee Meets sledujte na Eventbritu a přihlaste se k newsletteru – příští takový obsah vám přijde přímo do schránky.


