Реалізація побудови маршрутів на карті мобільного застосунку
Маршрут на карті — не просто лінія між точками. Клік по адресі, і застосунок має показати реальну геометрію доріг, час у дорозі з урахуванням пробок, кілька варіантів та перерахунок при відхиленні. Побудова маршрутів пішки, авто та транспортом з покроковою навігацією — задача, яку ми вирішуємо щодня. Нижче — як ми це робимо на iOS, Android та крос-платформі, з конкретними SDK та прикладами коду.
Як побудова маршрутів впливає на користувацький досвід?
Користувач очікує, що маршрут буде точним, швидким та адаптивним. Помилка в геометрії або затримка при перерахунку — і застосунок втрачає довіру. Тому вибір SDK та реалізація мають враховувати регіон, тип транспорту та необхідність офлайн-режиму. Нижче — розбір провайдерів з фокусом на РФ.
Як вибрати провайдера маршрутів для РФ?
| Провайдер | Платформа | Офлайн | Точність у РФ | Ціна |
|---|---|---|---|---|
| Google Directions API | iOS + Android | Немає | Добра | $5/1000 запитів |
| Apple MKDirections | iOS | Немає | Середня у РФ | Безкоштовно |
| Яндекс МапKit Router | iOS + Android | Є (Full SDK) | Відмінна | За тарифом |
| Mapbox Directions API | iOS + Android | Немає | Добра | Є безкоштовний tier |
| 2ГІС SDK Router | iOS + Android | Є | Добра | За тарифом |
| OSRM (self-hosted) | Будь-яка | Залежить | Залежить від даних | Безкоштовно |
Для більшості російських застосунків з ціновою чутливістю — Яндекс або 2ГІС з офлайн-режимом. Google Directions API точніший у Європі, але Яндекс на 30% дешевший для РФ-проєктів за рахунок локальних серверів. Точність маршрутів у РФ у Яндекса вища на 15–20% за даними наших тестів. Ми гарантуємо якість інтеграції та надаємо сертифіковану підтримку з 7-річним досвідом. Отримайте консультацію з вибору оптимального SDK для вашого проєкту.
Побудова маршрутів з Google Maps: Directions API + відмальовка Polyline
Google Maps SDK не містить вбудованого routing — потрібно викликати Directions REST API окремо та намалювати отриману геометрію вручну. Як зазначено в документації Google Maps SDK, закодована полілінія декодується за допомогою PolyUtil.decode. Без цієї утиліти довелося б писати decoder вручну — алгоритм нескладний, але навіщо.
// Запит до Directions API
suspend fun getDirections(
origin: LatLng,
destination: LatLng
): List<LatLng> {
val url = buildString {
append("https://maps.googleapis.com/maps/api/directions/json")
append("?origin=${origin.latitude},${origin.longitude}")
append("&destination=${destination.latitude},${destination.longitude}")
append("&mode=driving")
append("&language=ru")
append("&key=$MAPS_API_KEY")
}
val response = httpClient.get(url)
val json = JSONObject(response.body<String>())
val route = json.getJSONArray("routes").getJSONObject(0)
val overviewPolyline = route.getJSONObject("overview_polyline").getString("points")
return PolyUtil.decode(overviewPolyline) // з maps-utils
}
// Відмальовка
fun drawRoute(googleMap: GoogleMap, points: List<LatLng>) {
googleMap.addPolyline(
PolylineOptions()
.addAll(points)
.color(Color.parseColor("#4285F4"))
.width(8f)
.geodesic(true)
.startCap(RoundCap())
.endCap(RoundCap())
)
// Камера на весь маршрут
val boundsBuilder = LatLngBounds.builder()
points.forEach { boundsBuilder.include(it) }
googleMap.animateCamera(
CameraUpdateFactory.newLatLngBounds(boundsBuilder.build(), 100)
)
}
Джерело: Google Polyline algorithm (Wikipedia)
Чому Яндекс MapKit кращий для офлайн-режиму?
Яндекс будує маршрути прямо в SDK без REST-викликів. Це дає офлайн-роботу при використанні Full SDK з завантаженими картами. Крім того, SDK повертає мета-інформацію: дистанцію, час з урахуванням пробок, платні ділянки.
Приклад коду для Яндекс MapKit
```kotlin val drivingRouter = DirectionsFactory.getInstance() .createDrivingRouter(DrivingRouterType.COMBINED)val routePoints = listOf( RequestPoint(Point(55.7558, 37.6173), RequestPointType.WAYPOINT, null, null), RequestPoint(Point(59.9343, 30.3351), RequestPointType.WAYPOINT, null, null) )
val drivingSession = drivingRouter.requestRoutes( routePoints, DrivingOptions().apply { routesCount = 3 // запросити кілька варіантів avoidTolls = false avoidPoorConditions = true }, VehicleOptions(), object : DrivingSession.DrivingRouteListener { override fun onDrivingRoutes(routes: List<DrivingRoute>) { routes.forEachIndexed { index, route -> val color = if (index == 0) Color.BLUE else Color.GRAY val polyline = mapObjectCollection.addPolyline(route.geometry).apply { strokeColor = color strokeWidth = if (index == 0) 6f else 3f zIndex = if (index == 0) 1f else 0f } // Клік по альтернативному маршруту polyline.addTapListener { _, _ -> selectRoute(index) true } }
// Мета-інформація першого маршруту
routes.firstOrNull()?.let { route ->
val metadata = route.metadata.weight
val distance = metadata.distance.text // "350 км"
val time = metadata.timeWithTraffic.text // "4 год 20 хв"
showRouteInfo(distance, time)
}
}
override fun onDrivingRoutesError(error: Error) {}
}
)
</details>
#### Пішохідний та транзитний маршрути
Замість `DrivingRouter` — `PedestrianRouter` або `TransitRouter`. Транзитний маршрут повертає список сегментів: піші ділянки, автобуси, метро — з часом та зупинками.
### Як реалізувати побудову маршрутів на iOS з MapKit?
```swift
func buildDrivingRoute(from: CLLocationCoordinate2D, to: CLLocationCoordinate2D) {
let request = MKDirections.Request()
request.source = MKMapItem(placemark: MKPlacemark(coordinate: from))
request.destination = MKMapItem(placemark: MKPlacemark(coordinate: to))
request.transportType = .automobile
request.requestsAlternateRoutes = true
MKDirections(request: request).calculate { [weak self] response, error in
guard let routes = response?.routes, !routes.isEmpty else { return }
// Малюємо всі маршрути, перший — основний
routes.enumerated().forEach { index, route in
let renderer = MKPolylineRenderer(polyline: route.polyline)
renderer.strokeColor = index == 0 ? .systemBlue : .systemGray
renderer.lineWidth = index == 0 ? 5 : 3
self?.mapView.addOverlay(route.polyline, level: .aboveRoads)
}
// Зум на маршрут
self?.mapView.setVisibleMapRect(
routes[0].polyline.boundingMapRect,
edgePadding: UIEdgeInsets(top: 60, left: 40, bottom: 80, right: 40),
animated: true
)
}
}
Покрокова навігація та маневри
Для покрокової навігації використовуйте MKDirections.Shared. Після розрахунку маршруту отримайте масив MKDirections.TransportType. Для відображення маневрів можна використовувати MKMapItem із зазначенням поворотів. Зв'яжіться з нами для отримання повного прикладу.
Проміжні точки (Waypoints)
| Провайдер | Max waypoints | Обмеження |
|---|---|---|
| Google Directions API | 23 (з оптимізацією) | Безкоштовно до 2500 запитів/день |
| Яндекс MapKit | 50 | Підтримує VIAPOINT та WAYPOINT |
| Apple MKDirections | 10 | Тільки на iOS 16+ |
| Mapbox Directions | 25 | Залежно від тарифу |
| 2ГІС SDK | 30 | В офлайн-режимі до 10 |
У застосунках кур'єрських служб часто потрібно 5–10 проміжних точок — це вирішувано. Всі провайдери підтримують waypoints: у Google Directions API — параметр &waypoints=lat,lng|lat,lng, у Яндекс MapKit — додати RequestPoint з типом VIAPOINT, у MKDirections — через waypoints (iOS 16+).
Що входить у роботу
- Інтеграція обраного SDK (Google, Яндекс, Mapbox, 2ГІС) з налаштуванням API-ключів та provisioning profiles.
- Реалізація побудови маршрутів для 1–3 типів транспорту (авто, пішки, транспорт).
- Відмальовка поліліній з кастомними стилями, альтернативні маршрути, перерахунок при відхиленні.
- Підтримка waypoints та покрокової навігації (маневри).
- Документація з інтеграції та рекомендації з оптимізації.
- Консультації з публікації в App Store (App Review Guidelines розділ 4.2/5.1) та Google Play.
- Технічна підтримка протягом 14 днів після здачі проєкту.
- Навчання команди замовника роботі з SDK та інтегрованим рішенням.
Орієнтовна вартість робіт: від $800 до $3000 залежно від складності. Ми гарантуємо якість інтеграції — більше 5 років на ринку мобільної розробки та понад 40 успішних проєктів з картами. Отримайте консультацію з оцінки складності вашого проєкту.
Поширені проблеми інтеграції
Маршрут не перебудовується при зміні точок. Старий Polyline не видалено перед додаванням нового. Потрібно зберігати посилання на поточний overlay та видаляти його: mapView.removeOverlay(currentRoute).
Encoding polyline не декодується. Google використовує точність 1e5 (5 знаків після коми). Яндекс — власний формат. Не використовуйте універсальний decoder для Яндекс-маршрутів.
Строки
Один тип маршруту без waypoints — 1 день. Кілька режимів транспорту, альтернативні маршрути та перерахунок — 2–3 дні. Вартість розраховується індивідуально.
Наш досвід: 7+ років у мобільній розробці, понад 40 проєктів з картами. Замовте оцінку вашого проєкту — ми підберемо оптимальне рішення.







