A real-time car tracking Android application built with Jetpack Compose and the Neshan Maps SDK.
- Real-time car location tracking on a map
- Fetch car locations from a backend API
- User location detection via GPS
- Route planning between user and selected car (using Neshan Routing API)
- Travel mode toggle (car / pedestrian)
- Persian (Farsi) UI with RTL layout
- Login screen with basic authentication
- Kotlin — Primary language
- Jetpack Compose — UI toolkit (Material3)
- Neshan Maps SDK — Map rendering, markers, polylines
- Retrofit + OkHttp — Networking (Gson converter, logging interceptor)
- Google Play Services Location — GPS location provider
- Coroutines — Async operations
app/src/main/java/ir/nhazerakhsh/car_tracker/
├── data/
│ ├── model/ # Data classes (CarLocation, NeshanDirectionResponse)
│ └── repository/ # Repository layer (CarRepository)
├── network/ # Retrofit services & client
│ ├── CarApiService.kt # Car locations API
│ ├── NeshanApiService.kt # Neshan routing API
│ └── RetrofitClient.kt # Retrofit singleton instances
├── ui/
│ ├── screen/ # Composable screens (LoginScreen, MapScreen)
│ └── theme/ # Material3 theme (colors, typography, shapes)
├── util/
│ └── PolylineDecoder.kt # Google Encoded Polyline decoder
└── MainActivity.kt # Single Activity entry point
- Android Studio (latest)
- JDK 17+
- Android SDK 36
- Neshan Maps SDK — License file at
app/src/main/res/raw/neshan.license - Neshan Routing API — API key hardcoded in
MapScreen.kt(replace with your own) - Car Backend API — Configure
CAR_API_BASE_URLinnetwork/RetrofitClient.kt
./gradlew assembleDebugThe app fetches car locations from a backend API. The endpoint and expected response format are defined in CarApiService.kt:
- Endpoint:
GET /api/v1/cars/locations - Response:
List<CarLocation>— JSON array of car objects
Each car object:
{
"car_name": "Peugeot 206",
"lat": 35.7010,
"lng": 51.3907,
"timestamp": 1712345678000
}Edit RetrofitClient.kt:
const val CAR_API_BASE_URL = "http://10.0.2.2:3000/"Default points to 10.0.2.2:3000 (host machine's localhost from Android emulator). Change to your actual backend URL for production or physical device testing.
CarRepository wraps the API call with Result for easy error handling:
val repository = CarRepository()
repository.getCarLocations()
.onSuccess { cars -> /* update UI */ }
.onFailure { error -> /* handle error */ }While this app uses a mock backend by default, it is designed to be easily integrated with production-ready services.
To secure your API with JSON Web Tokens:
- Auth: Implement a
/loginendpoint returning a token. - Interceptors: Update
RetrofitClient.ktto include anAuthInterceptor:val authInterceptor = Interceptor { chain -> val request = chain.request().newBuilder() .addHeader("Authorization", "Bearer $YOUR_TOKEN") .build() chain.proceed(request) } // Add to OkHttpClient.Builder()
Supabase provides built-in Auth and Realtime capabilities:
- Auth: Use the
supabase-ktSDK to handlesignInWithEmail. - Location: Use Supabase Realtime or PostgREST to fetch car locations.
- Setup:
val supabase = createSupabaseClient(url, key) { install(Auth) install(Realtime) }
Firebase is a great alternative for rapid development:
- Auth: Use
FirebaseAuthfor email/password or social login. - Location: Store car coordinates in Firestore or Realtime Database.
- Real-time updates: Use
addSnapshotListenerto get live location updates on the map without polling.
All rights reserved.