Mobile App for Public Transport (Schedule and Payment)
A public transport app works under constantly changing data: schedules change by holidays and seasons, routes edited, transport delayed. Static schedule database becomes outdated in a week. Real-time arrival is more interesting to user than theoretical schedule.
GTFS and Real-Time
Standard for schedule data exchange — GTFS (General Transit Feed Specification). Most city transit systems publish GTFS feeds: set of CSV files with routes, stops, times. For real-time — GTFS-RT (Realtime): Protobuf streams with TripUpdate, VehiclePosition, ServiceAlert.
On client: Protobuf parsing via protobuf-kotlin / Swift SwiftProtobuf. GTFS-RT updates every 15-30 seconds — polling or Server-Sent Events. VehiclePosition feed gives vehicle coordinates for map display.
If city operator doesn't provide GTFS-RT — can implement arrival prediction based on static schedule + historical delay data. Worse than real-time, but better than nothing.
Offline Schedule and Caching
User in metro without internet — schedule must be available. Strategy: on first launch, download full GTFS bundle (~5-20 MB for average city), save in SQLite via Room (Android) / GRDB (iOS). Schedule queries — SQL on local DB, no network.
Background update: WorkManager (Android) with NetworkConstraint checks GTFS feed version once daily, on update — downloads delta or full feed. BGAppRefreshTask (iOS) for similar update.
Real-time cache: VehiclePosition and TripUpdate data live no longer than 60 seconds, store in memory (not SQLite), clear on expiration.
Route Building with Transfers
Route from stop A to stop B with possible transfers — task for transit routing engine. Options:
Google Maps Directions API with mode=transit — simplest. Returns route with transfers, times, line names. But: paid, no access to raw data, Google dependency.
OpenTripPlanner — open source transit router, works with GTFS. Deployed on own server, client makes requests. Full data control, free for own server.
Raptor algorithm — fast transit routing, can implement server-side in Kotlin/Java. For small city (up to 200 routes) works in milliseconds.
On client: route display with transfers — timeline view with line color coding, time per segment, transport icons.
Payment
Payment in app — QR code or NFC.
QR variant: after payment, QR generated with token (JWT or random string), verified on terminal in transport. One-time use token, lives 30-60 minutes.
NFC: Host Card Emulation (HCE) on Android — emulate contactless card, HostApduService. iOS before 17 didn't support third-party NFC payments, iOS 17.4+ limited availability in EU. For most cases — QR code more reliable.
Apple Pay / Google Pay as balance top-up method in app — yes, works everywhere. Transit gate pass itself — HCE or QR.
Transport card in app: balance, top-up history, trip history. Top-up via card, Apple Pay, Google Pay. Push on low balance.
Map with Stops and Transport
Stop clustering at low zoom, expand on approach. Tap stop — nearest departures in real-time: pull from GTFS-RT TripUpdate feed.
Vehicle markers real-time from VehiclePosition. Movement animation — position interpolation (15-30 sec update interval, smooth movement during that). Route icon on marker: line number, color from GTFS routes.txt.
Stack
Android: Kotlin, Jetpack Compose, Room, WorkManager, Google Maps SDK or Mapbox. iOS: Swift, SwiftUI, GRDB, BackgroundTasks, MapKit or Mapbox. Cross-platform: Flutter with native modules for NFC and background tasks.
Phases: GTFS source integration → offline DB → transit routing → real-time → payment → testing on real city routes → release.
Timeline: 12 to 22 weeks. Cost calculated individually.







