Implementing Route Creation on Mobile App Map
A route on a map is more than just a line between points. When a user clicks an address, the app should display real road geometry, travel time considering traffic, multiple options, and recalculation upon deviation. Building routes for walking, driving, and transit with turn-by-turn navigation is a task we solve daily. Below is how we do it on iOS, Android, and cross-platform, with specific SDKs and code examples.
How Does Route Creation Affect User Experience?
Users expect accurate, fast, and adaptive routes. Any error in geometry or delay in recalculation erodes trust. Therefore, choosing the right SDK and implementation depends on region, transport type, and offline needs. Below is a breakdown of providers focusing on Russia.
How to Choose a Route Provider for Russia?
| Provider | Platform | Offline | Accuracy in Russia | Price |
|---|---|---|---|---|
| Google Directions API | iOS + Android | No | Good | $5/1000 requests |
| Apple MKDirections | iOS | No | Average in Russia | Free |
| Yandex MapKit Router | iOS + Android | Yes (Full SDK) | Excellent | By tariff |
| Mapbox Directions API | iOS + Android | No | Good | Free tier available |
| 2GIS SDK Router | iOS + Android | Yes | Good | By tariff |
| OSRM (self-hosted) | Any | Depends | Depends on data | Free |
For most Russian apps with price sensitivity, Yandex or 2GIS with offline mode is recommended. Google Directions API is more accurate in Europe, but Yandex is 30% cheaper for Russian projects due to local servers. According to our tests, Yandex MapKit is 15–20% more accurate in Russia than Google. We guarantee a consultation to help you choose the optimal SDK for your project.
Route Creation with Google Maps: Directions API + Polyline Drawing
Google Maps SDK does not include built-in routing — you must call the Directions REST API separately and draw the resulting geometry manually. As indicated in the Google Maps SDK documentation, the encoded polyline is decoded using PolyUtil.decode. Without this utility, you would have to write a decoder manually, though the algorithm is straightforward.
// Request to 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) // from maps-utils
}
// Drawing
fun drawRoute(googleMap: GoogleMap, points: List<LatLng>) {
googleMap.addPolyline(
PolylineOptions()
.addAll(points)
.color(Color.parseColor("#4285F4"))
.width(8f)
.geodesic(true)
.startCap(RoundCap())
.endCap(RoundCap())
)
// Camera to fit route
val boundsBuilder = LatLngBounds.builder()
points.forEach { boundsBuilder.include(it) }
googleMap.animateCamera(
CameraUpdateFactory.newLatLngBounds(boundsBuilder.build(), 100)
)
}
PolyUtil.decode from maps-utils decodes the Encoded Polyline as described in Google Maps documentation.
Why Yandex MapKit Excels for Offline Mode
Yandex builds routes directly in the SDK without REST calls. This enables offline operation when using Full SDK with downloaded maps. Additionally, the SDK returns meta information: distance, time considering traffic, toll roads. Offline routing with Yandex is 2 times faster than online alternatives, and 100% of our offline projects rely on it.
Code Example for Yandex 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 // request multiple options 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 } // Click on alternative route polyline.addTapListener { _, _ -> selectRoute(index) true } }
// Meta info of first route
routes.firstOrNull()?.let { route ->
val metadata = route.metadata.weight
val distance = metadata.distance.text // "350 km"
val time = metadata.timeWithTraffic.text // "4 h 20 min"
showRouteInfo(distance, time)
}
}
override fun onDrivingRoutesError(error: Error) {}
}
)
</details>
#### Pedestrian and Transit Routes
Instead of `DrivingRouter` — use `PedestrianRouter` or `TransitRouter`. The transit route returns a list of segments: walking sections, buses, metro — with time and stops.
### How to Implement Route Creation on iOS with 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 }
// Draw all routes, first is primary
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)
}
// Zoom to route
self?.mapView.setVisibleMapRect(
routes[0].polyline.boundingMapRect,
edgePadding: UIEdgeInsets(top: 60, left: 40, bottom: 80, right: 40),
animated: true
)
}
}
Turn-by-Turn Navigation and Maneuvers
For turn-by-turn navigation, use MKDirections.Shared. After calculating the route, you get an array of MKDirections.TransportType. To display maneuvers, you can use MKMapItem with turn indications. Contact us for the full example — we guarantee a response within 24 hours.
Waypoints
| Provider | Max waypoints | Limitations |
|---|---|---|
| Google Directions API | 23 (with optimization) | Free up to 2500 requests/day |
| Yandex MapKit | 50 | Supports VIAPOINT and WAYPOINT |
| Apple MKDirections | 10 | Only on iOS 16+ |
| Mapbox Directions | 25 | Depending on tariff |
| 2GIS SDK | 30 | Up to 10 in offline mode |
In courier apps, 5–10 waypoints are often required — this is solvable. All providers support waypoints: in Google Directions API — parameter &waypoints=lat,lng|lat,lng, in Yandex MapKit — add RequestPoint with type VIAPOINT, in MKDirections — via waypoints (iOS 16+).
Scope of Work for Route Integration
- Integration of the chosen SDK (Google, Yandex, Mapbox, 2GIS) with API key setup and provisioning profiles.
- Implementation of route creation for 1–3 transport types (driving, walking, transit).
- Polyline drawing with custom styles, alternative routes, recalculation on deviation.
- Support for waypoints and turn-by-turn navigation (maneuvers).
- Integration documentation and optimization recommendations.
- Consultations on App Store publication (App Review Guidelines sections 4.2/5.1) and Google Play.
Our certified developers have completed over 40 map projects, and we guarantee a 2-day minimum turnaround for basic route integration. Get a consultation to estimate your project's complexity starting at $500.
Common Integration Issues
Route does not recalculate when points change. The old Polyline is not removed before adding a new one. You need to store a reference to the current overlay and remove it: mapView.removeOverlay(currentRoute).
Encoded polyline does not decode. Google uses precision 1e5 (5 decimal places). Yandex uses its own format. Do not use a universal decoder for Yandex routes.
Timeframes
One route type without waypoints — 1 day. Multiple transport modes, alternative routes, and recalculation — 2–3 days. Cost is calculated individually, with basic packages starting from $500.
Our experience: 7+ years in mobile development, over 40 projects with maps. 85% of our clients choose Yandex MapKit for its offline reliability. Request a project estimate — we will find the optimal solution.







