Нативна розробка Android-додатків на Kotlin
Замовник приходить до нас із готовим дизайном, іноді з прототипом на Figma, і питає: «Чому не можна просто взяти React Native?» Відповідь залежить від того, що саме потрібно додатку. Якщо це робота з Bluetooth LE, складна навігація по стеку екранів, фонова геолокація або запис екрану — нативний Android на Kotlin позбавляє цілого класу проблем, які в крос-платформі вирішуються через костилі та нативні модулі, тобто фактично тим самим кодом, тільки прихованим за абстракцією.
Kotlin — основна мова Android-розробки з 2019 року. Google переписує власні бібліотеки з Java на Kotlin, Jetpack Compose існує тільки на Kotlin, і нові API на кшталт kotlinx.coroutines або Flow просто не мають повноцінних аналогів для Java-стека. Вибір Kotlin — це не вподобання, а слідування екосистемі.
Чому Kotlin і Jetpack Compose — стандарт індустрії?
Jetpack Compose — це не новомодна технологія, а вже стандарт для UI в Android. Compose прибирає розрив між станом і UI: немає notifyDataSetChanged(), немає ViewHolder бойлерплейта, немає синхронізації між XML і кодом. @Composable-функція просто описує, як виглядає UI при даному стані, і Compose сам перераховує те, що змінилося, через smart recomposition. За продуктивністю рендерингу Compose у 2–3 рази швидший за React Native при роботі з анімаціями.
З чого насправді складається сучасний Android-проєкт
Архітектура типового комерційного додатка виглядає так: Clean Architecture з розбивкою на шари data / domain / presentation, MVVM як патерн presentation-шару, Hilt для dependency injection. Навігація — через Navigation Component з NavGraph або більш гнучкий Decompose для складних вкладених стеків.
UI будується на Jetpack Compose. Для управління станом використовуємо StateFlow + ViewModel. Для складних UI з shared state між кількома екранами — MVI-патерн з єдиним UiState і UiEffect. Бізнес-логіка живе в UseCase-класах, які не знають про Android-специфіку і легко покриваються unit-тестами без Robolectric.
Мережевий шар: Retrofit 2 + OkHttp з ланцюжком інтерсепторів для авторизації, логування та retry-логіки. Серіалізація — kotlinx.serialization або Moshi за вподобаннями команди. Локальне сховище — Room з TypeConverters для кастомних типів і @Transaction для атомарних операцій.
Фонові задачі — WorkManager для відкладених і періодичних операцій, корутини з правильними CoroutineScope для одноразових задач. Проблема «корутина запущена, Activity померла, потік потоку» вирішується через viewModelScope і repeatOnLifecycle.
Як запобігти типовим помилкам при розробці?
Проблема не в написанні коду — у рішеннях, які приймаються в перші два тижні. Ось де виникають найдорожчі помилки і як ми їх уникаємо:
Навігація без чіткої схеми. У Navigation Component спокусливо додавати фрагменти в міру необхідності. Через три місяці виходить граф, в якому неможливо зрозуміти, звідки прийшов користувач і куди повернеться після deep link. Ми проєктуємо NavGraph заздалегідь, виділяємо вкладені графи для кожного feature-модуля, і backstack не перетворюється на загадку.
Неправильний lifecycle. collectAsStateWithLifecycle() замість collectAsState() — здавалося б, дрібниця. Але без правильного lifecycle-aware collection Flow продовжує працювати, коли додаток у фоні, і батарея сідає. Краші з Firebase Crashlytics з IllegalStateException: Cannot collect flow on a dead lifecycle говорять саме про це.
Багатопоточність на головному потоці. Доступ до бази даних Room на main thread у debug-збірці кидає IllegalStateException — це добре, одразу видно. Але декодування Bitmap 4K-фото в onBindViewHolder при використанні старого RecyclerView-підходу не кидає винятків, просто дропає фрейми. Coil і Glide вирішують це через корутини та worker threads, але тільки якщо правильно налаштований ImageLoader.
Неправильні scope у Hilt-компонентів. @Singleton репозиторій з @ActivityScoped залежністю всередині — і Hilt чесно падає з [Dagger/MissingBinding] на збірці. Не в рантаймі — на збірці. Це добре, але розібратися в довгому stack trace Dagger-кодогенерації вміє не кожен.
Чому нативний Kotlin вигідніший для складних проєктів?
Порівняння нативного підходу з крос-платформними фреймворками показує: для проєктів з високим навантаженням на графіку, складною анімацією або специфічними апаратними функціями (Bluetooth, NFC, камера) нативний код забезпечує 100% стабільність. Крос-платформа дає економію часу на старті, але потім потребує постійних доопрацювань нативних модулів. На практиці команда витрачає до 40% часу на обхідні шляхи в React Native, яких у нативному коді просто не існує.
| Критерій | Нативний Kotlin | React Native |
|---|---|---|
| Продуктивність анімацій | 60 FPS стабільно | Часто просадки до 30-40 FPS |
| Доступ до нових API | Одразу при виході | Через мости, затримка 2-4 тижні |
| Складність налагодження | Android Studio + Profiler | Chrome Dev Tools, обмежений профайлер |
Як будується робота
Починаємо з технічного аудиту вимог: список екранів, інтеграції (API, SDK третіх сторін, push через FCM, аналітика через Firebase/Amplitude), вимоги до offline-режиму, мінімальна підтримувана версія API (зазвичай API 24 / Android 7.0, рідше API 21).
Далі — архітектурне рішення: монолітний модуль або multi-module project. Multi-module прискорює інкрементальні збірки Gradle та забезпечує ізоляцію feature-команд, але додає складність у налаштуванні залежностей між модулями. Для проєктів до 5-7 feature-команд моноліт з чіткими package-boundaries практичніший.
Розробка йде спринтами по 1-2 тижні з демо в кінці кожного. CI налаштовується з першого дня: GitHub Actions або GitLab CI, збірка + unit-тести + lint на кожен PR, Firebase App Distribution для дистрибуції тестових збірок.
Тестування: unit-тести на UseCase та ViewModel (покриття 95%), UI-тести через Compose Testing API. Для складних flow — інтеграційні тести з in-memory Room database.
Перед публікацією — обфускація через R8, перевірка android:exported для всіх компонентів (вимога Google Play з API 31), тестування на кількох пристроях різних виробників через Firebase Test Lab.
Що входить у роботу
- Детальний технічний аудит вимог і складання ТЗ
- Проєктування архітектури (Clean Architecture + MVVM/MVI)
- Розробка з використанням Jetpack Compose, Hilt, Retrofit, Room
- Написання unit-тестів та UI-тестів (покриття >90%)
- Налаштування CI/CD (GitHub Actions/GitLab CI + Firebase App Distribution)
- Оптимізація збірки та обфускація (R8)
- Публікація в Google Play Console з проходженням усіх перевірок
- Документація з архітектури та деплою
- Технічна підтримка після релізу
Орієнтири за строками
| Тип проєкту | Оцінка |
|---|---|
| MVP з 5-8 екранами та REST API | 4-6 тижнів |
| Додаток зі складною бізнес-логікою, offline, push | 8-12 тижнів |
| Комплексний продукт з кількома інтеграціями | 3+ місяці |
Вартість розраховується індивідуально після аналізу вимог. Отримайте консультацію та попередню оцінку вашого проєкту — зв'яжіться з нами.
Що впливає на складність найбільше?
Не кількість екранів — а інтеграції. FCM з rich notifications та custom sounds — три дні. Біометрична авторизація через BiometricPrompt API з fallback на PIN — день-два. Робота з Bluetooth LE через BluetoothGatt на кількох пристроях одночасно — окремий проєкт всередині проєкту, тому що виробники по-різному реалізують GATT-стек.
Карти: Google Maps SDK підключається за годину, але кастомні маркери з кластеризацією, полігони та офлайн-тайли — це вже кілька днів. In-app purchases через Google Play Billing Library 6.x з підписками, промо-кодами та graceful degradation при недоступності Play Store — легко тиждень роботи.
Весь цей scope потрібно розуміти до початку розробки. Тому перший крок — детальне ТЗ, а не оцінка «на око».
Типові помилки, яких ми не допускаємо
- Використання Flow без правильного lifecycle-aware collection
- Змішування UI-логіки та бізнес-логіки в Activity/Fragment
- Відсутність модульності у великих проєктах
- Нехтування конфігурацією R8 перед публікацією
- Недостатнє тестування на реальних пристроях
Гарантуємо якість: 5+ років досвіду, понад 30 завершених проєктів. Замовте розробку Android-додатка на Kotlin — отримайте сучасне, продуктивне та надійне рішення.







