Розроблення мобільного додатку для подорожей (TravelTech)
Бронювання авіабилета через мобільний браузер — це 12 екранів, які користувач повинен пройти за 3 хвилини до посадки в самолет, стоячи в черзі на паспортний контроль. Якщо на будь-якому екрані станеться таймаут сесії, cold start після сворачування додатку, або карта зависнет через недозавантажені тайли — він уйде до конкурента. TravelTech-додатки не прощають нестабільності.
Що відрізняє travel-додаток від інших вертикалей
Головна біль — гетерогенні зовнішні API з непередбачуваним SLA. Amadeus GDS повертає відповідь за 800 мс в найкращому випадку, в піковий сезон — за 4–6 секунд. Якщо показувати скелетон та блокувати весь екран, користувач натискає «назад» через 2 секунди. Правильне рішення — прогресивна загрузка: спочатку отдаємо кешовані результати з Room/CoreData (попередні поіски), паралельно запускаємо свіжий запит, оновлюємо список через DiffUtil/diffableDataSource без перерисовки всього екрана.
Другий вузький момент — офлайн-режим. Турист в роумінгу за кордоном з дорогим трафіком не може завантажити карту маршруту. Працюємо з MapLibre GL Native та предзавантажуємо тайлові пакети (.mbtiles) по регіону перед подорожею — користувач вибирає країну, завантажує ~40–120 МБ, та потім навігація працює без мережі. На iOS це добре поєднується з URLSession background transfer для фонової загрузки під час зарядки.
Інтеграція з системними Calendar API (EventKit на iOS, CalendarContract на Android) дозволяє додавати рейси, брони готелів та тури прямо в системний календар з глибокими посиланнями назад в додаток. Користувачі не помічають, наскільки це зручно, поки це не ломається.
Бронювання та реальний час
Робота з booking-рухам (Amadeus, Sabre, Travelport) або агрегаторами (TravelFusion, Duffel API) будується на polling або webhook-паттерні. Duffel надає REST з хорошою документацією, Amadeus вимагає OAuth 2.0 та розуміння їх NDC-протоколу. В обох випадках результат пошуку потрібно зберігати локально (encrypted SQLCipher або iOS Data Protection) — користувач повернеться через 20 хвилин та очікує бачити той же варіант.
Для push-сповіщень про зміну статусу рейсу використовуємо Firebase Cloud Messaging (Android) та APNs (iOS) з content-available: 1 для silent push — додаток оновлює дані в фоні через BGAppRefreshTask без пробудження користувача.
Карти та маршрути
| Сценарій | Технологія | Примітка |
|---|---|---|
| Онлайн-карта з POI | Google Maps SDK / MapKit | Готові стилі, швидка інтеграція |
| Офлайн-навігація | MapLibre GL Native | Відкритий вихідний, свої тайли |
| Пішохідні маршрути | OpenRouteService API | Пішохідні, велосипедні профілі |
| AR-путеводитель | ARKit / ARCore | Накладення POI на камеру |
AR-путеводителі — окремена історія. На Android ARCore вимагає пристрій з підтримкою Depth API для стабільного розміщення об'єктів у просторі. На старих Pixel 3 без LiDAR об'єкти «плавають» при русі. Це чесно говорити клієнту на етапі проектування.
Стек та архітектура
Для крос-платформенних TravelTech-проектів найчастіше обираємо Flutter з BLoC або Riverpod. Причина прагматична: Dart Isolates дозволяють парсити великі JSON-відповіді (списки рейсів на 500+ записів) поза main isolate без джанків в UI. На нативе Android — Kotlin Coroutines + Flow, iOS — Swift Concurrency з async/await. Архітектура — Clean Architecture з розбивкою на data/domain/presentation шари; це не релігія, а необхідність, коли у вас 4 різних джерелами даних для одного екрана.
Локалізація — окремий модуль. Працюємо з ICU message format через intl (Flutter) або Lokalise SDK. Дати, валюти та формати телефонів не хардкодимо — NumberFormat.currency(locale: userLocale) замість ручного додавання символів.
З практики
Проект: агрегатор турів для СНГ-ринку. Flutter, 3 платформи (iOS / Android / Web через Flutter Web). Головна проблема після запуску — OOM crash на Android при листанні списку з 300+ турів з зображеннями. Причина: Image.network без cacheWidth/cacheHeight завантажував оригіналів 4K в пам'ять. Рішення — CachedNetworkImage з явним memCacheWidth та lazy loading через flutter_staggered_grid_view з жорстким addRepaintBoundaries: true. Після фіксу потребування пам'яті упало з пікових 380 МБ до 140 МБ на Redmi Note 10.
Етапи роботи
- Аудит вимог — розбираємо, які зовнішні API вже є у клієнта (GDS-контракти, партнерські угоди), що потрібно інтегрувати з нуля
- Проектування архітектури — схема даних, offline-first або online-first, стратегія кешування
- UI/UX — Figma-прототип, узгодження флоу бронювання
- Розроблення — ітераціями по вертикальним срізам (спочатку пошук, потім бронювання, потім профіль)
- Тестування — Appium для E2E, XCTest/Espresso для unit/integration, нагрузкове на API-інтеграції
- Публікація — App Store Connect + Google Play Console, Fastlane для автоматизації
- Підтримка — моніторинг через Firebase Crashlytics + Sentry, A/B тесты через Firebase Remote Config
Тривалість залежить від обсягу: MVP з пошуком рейсів та бронюванням готелів — від 3 місяців. Повноцінний travel-суперапп з маршрутами, AR-функціями та офлайн-картами — 6–12 місяців. Вартість розраховується після детального аналізу вимог та аудиту існуючих API-контрактів.







