Developing a Mobile App for Taxi
A taxi app is one of the technically dense mobile tasks. Not because any single component is complex, but because several systems converge: geolocation, real-time tracking, driver matching, cost calculation, payment gateway, push notifications, offline support. Problems arise at intersections.
Two Apps and One Backend
Passenger app and driver app—different products with different logic, shared API. Design them as single system from start, not retrofit—otherwise API grows unpredictably.
Minimum system:
- Passenger app (iOS + Android)
- Driver app (iOS + Android)
- Backend API (REST + WebSocket/MQTT)
- Admin panel (optional on first stage)
Geolocation and Driver Search
Key scenario: passenger opens app → sees nearby drivers on map → optimal one assigned → watches real-time movement.
Drivers in waiting mode send coordinates every 5-10 seconds. Server stores live positions in Redis Geo: GEOADD drivers_online {lon} {lat} {driver_id}. Find nearest: GEORADIUS drivers_online {lon} {lat} 3 km WITHCOORD WITHDIST COUNT 10 ASC—returns driver IDs within 3 km radius, sorted by distance, in milliseconds.
After driver assignment—WebSocket channel between passenger and driver. Proxy server forwards driver coordinates only to assigned passenger. Broadcasting all drivers to all passengers—wrong architecture.
Route Calculation and Pricing
Google Directions API or OSRM (self-hosted, free) for calculating route from driver to passenger and passenger to destination. Response contains distance (meters) and duration (seconds)—basis for estimated cost.
Pricing formula: base_price + per_km * distance_km + per_min * duration_min. Plus demand coefficient (surge pricing)—stored on server, multiplied during driver shortage. Always calculate final price on server, not client—client just displays.
Dynamic pricing. Estimated price vs final: show passenger pre-calculated cost before trip, fix final based on actual route. Limit difference ±15-20%—otherwise users complain about unexpected charges.
Driver App: Key Screens and Logic
Online/offline mode. Transitioning online—start Foreground Service (Android) / background location (iOS), coordinates begin sending. Driver appears in Redis Geo. Offline—service stops, driver disappears from pool.
Incoming order. Push notification + WebSocket event simultaneously. WebSocket if active has priority (faster). Sound + vibration, 15-20 second timer to accept. No response—order passed to next driver.
Navigation. After accepting—map route with turn-by-turn directions. Can use native navigation: MKMapItem.openMaps() on iOS or Intent(ACTION_VIEW, Uri.parse("google.navigation:q=...")) on Android. Or embed via Mapbox Navigation SDK—costlier development, but user stays in app.
Trip statuses. accept → arriving → waiting → in_progress → completed. Each transition—explicit driver action (button), not automatic. Automatic only for timeouts.
Passenger App
Order screen. Map with current position, destination address input with autocomplete (Google Places API or DaData), vehicle class selection, estimated cost, "Order" button.
After ordering. Animated driver marker moves to passenger. Distance and ETA update real-time via WebSocket. Driver data: name, photo, rating, vehicle make and license plate.
During trip. Route on map, current position, estimated arrival time. SOS button → call security service or emergency contact.
After trip. Rate driver (1-5 stars), tips, receipt via email/SMS.
Payment Integration
Russia—CloudPayments, YooKassa (ЮКасса), Tinkoff Acquiring. SDKs for iOS and Android ready, integration takes a day. Important: save card via tokenization—real card number not stored in app or servers, only token.
CloudPayments iOS SDK: CPCloudPayments → CRPaymentForm.present(with:). Android: CloudPaymentsApi.doPay(context, cryptogram, saveCard).
Apple Pay / Google Pay—priority for users without saved card. PKPaymentAuthorizationViewController iOS, PaymentsClient Google Pay API Android.
Push Notifications
Firebase Cloud Messaging (FCM)—both iOS and Android via single SDK. APNs for iOS works via FCM layer. Notification types: incoming order to driver, driver arriving (passenger), trip completed, receipt.
Critical scenario: incoming order notification must wake driver app if backgrounded. Android—data notification (not notification) triggers onMessageReceived even in background. iOS—content-available: 1 for silent push + regular alert for display.
Stack
| Component | Technologies |
|---|---|
| iOS | Swift, SwiftUI/UIKit, GoogleMaps SDK, FCM |
| Android | Kotlin, Jetpack Compose, Google Maps SDK, FCM |
| Flutter (optional) | Dart, google_maps_flutter, firebase_messaging |
| Backend | Node.js / Go / Python (FastAPI), WebSocket, Redis Geo, PostgreSQL + PostGIS |
| Payments | CloudPayments / YooKassa + Apple Pay / Google Pay |
Timeline
Minimum MVP (one platform passenger + driver, basic navigation, one payment method): six-ten weeks.
Full app (both platforms, surge pricing, trip history, admin panel, analytics): four-six months.
Cost estimated individually after requirement analysis and task decomposition.







