Visla GPS Mobile Apps Documentation
Overview
Native mobile applications for Visla GPS platform, built with modern technologies:
- iOS: SwiftUI + Swift 5
- Android: Kotlin + Jetpack Compose
Both apps provide:
- User authentication
- Push notification handling (FCM)
- Centralized logging to Grafana
Project Structure
iOS (visla-gps-ios/)
VislaGPS/
├── VislaGPSApp.swift # App entry point, navigation
├── AppDelegate.swift # Firebase init, push notifications
├── ContentView.swift # Main home screen
├── LoginView.swift # Login screen
├── ApiClient.swift # HTTP client, auth, API calls
├── Logger.swift # Centralized logging
├── Info.plist # App configuration
├── GoogleService-Info.plist # Firebase config
└── LaunchScreen.storyboard # Launch screen
Android (visla-gps-android/)
app/src/main/java/com/visla/vislagps/
├── MainActivity.kt # Main activity, navigation
├── VislaGPSApp.kt # Application class
├── ApiClient.kt # HTTP client, auth
├── Logger.kt # Centralized logging
├── NotificationManager.kt # FCM state management
├── service/
│ └── FCMService.kt # Firebase messaging service
└── ui/
├── theme/Theme.kt # Dark theme colors
└── screens/
├── HomeScreen.kt # Main screen
└── LoginScreen.kt # Login screen
Configuration
Base URL
Both apps are configured to use:
https://api.vislagps.com
To change, edit:
- iOS:
ApiClient.swift→baseURLproperty - Android:
ApiClient.kt→BASE_URLconstant
Firebase
| Platform | Config File |
|---|---|
| iOS | GoogleService-Info.plist |
| Android | app/google-services.json |
Project: visla-gps-d15d6
Package: com.visla.vislagps
Authentication
Login Flow
1. User enters email/password
2. App calls POST /api/auth/login
3. Server returns { accessToken, user }
4. App stores JWT + user_id locally
5. App registers FCM token with backend
6. Navigate to HomeScreen
API Endpoints Used
| Endpoint | Method | Auth | Description |
|---|---|---|---|
/api/auth/login | POST | No | User login |
/api/notifications/tokens | POST | JWT | Register FCM token |
/api/logs | POST | JWT | Send logs |
/api/logs/batch | POST | JWT | Send batch of logs |
Storage
| Platform | Storage Method |
|---|---|
| iOS | UserDefaults |
| Android | SharedPreferences |
Push Notifications
Setup
- Firebase is initialized on app launch
- App requests notification permission (iOS 10+, Android 13+)
- FCM token is fetched
- After login, token is registered with backend
Token Registration
POST /api/notifications/tokens
Authorization: Bearer <jwt>
{
"user_id": 123,
"token": "fcm_token_here",
"platform": "ios", // or "android"
"device_name": "iPhone 15"
}
Receiving Notifications
Notifications are received via FCMService (Android) or AppDelegate (iOS) and displayed in the app's notification log with:
- Title
- Body
- Timestamp
- Expandable payload
Logging
Usage
// iOS
Logger.shared.debug("Debug message")
Logger.shared.info("User action", context: ["screen": "Home"])
Logger.shared.warn("Warning message")
Logger.shared.error("Error occurred", context: ["code": "500"])
// Android
Logger.debug("Debug message")
Logger.info("User action", mapOf("screen" to "Home"))
Logger.warn("Warning message")
Logger.error("Error occurred", mapOf("code" to "500"))
Log Levels
| Level | Use Case |
|---|---|
debug | Development debugging |
info | User actions, successful operations |
warn | Non-critical issues |
error | Failures, exceptions (sent immediately) |
Backend Flow
Mobile App → POST /api/logs/batch → mobile-logs service → Loki → Grafana
Grafana Queries
{job="mobile-logs"} # All mobile logs
{job="mobile-logs", platform="ios"} # iOS only
{job="mobile-logs", platform="android"} # Android only
{job="mobile-logs", level="error"} # Errors only
{job="mobile-logs", level="error"} |= "login" # Errors containing "login"
Logged Events
| Event | Level | Source | Description |
|---|---|---|---|
App launched | info | AppDelegate/MainActivity | App started |
Login attempt | info | LoginView/LoginScreen | User attempting login |
Login successful | info | LoginView/LoginScreen | Login succeeded (includes user_id) |
Login failed | error | LoginView/LoginScreen | Login failed (includes error) |
User logged out | info | ContentView/HomeScreen | User tapped logout |
Notification permission | info | AppDelegate/MainActivity | Permission granted/denied |
FCM token received | info | AppDelegate/MainActivity | Token fetched (prefix only) |
FCM token refreshed | info | FCMService | Token updated |
FCM token registered with backend | info | AppDelegate/MainActivity | Token sent to server |
FCM token registration failed | error | AppDelegate/MainActivity | Server registration failed |
Push received (foreground) | info | AppDelegate | Push notification in foreground |
Push received | info | FCMService | Push notification received |
Push tapped | info | AppDelegate | User tapped notification |
Building & Deploying
iOS
- Open
VislaGPS.xcodeprojin Xcode - Select target device
- Product → Build (⌘B)
- For App Store:
- Product → Archive
- Validate & Upload
Requirements:
- Xcode 15+
- iOS 15.0 minimum deployment target
Android
- Open
visla-gps-android/in Android Studio - Sync Gradle
- Run → Run 'app'
- For Play Store:
- Build → Generate Signed Bundle / APK
- Select "Android App Bundle"
Requirements:
- Android Studio Hedgehog+
- Android SDK 35
- Kotlin 1.9.22
Version Info
| Platform | Version | Build |
|---|---|---|
| iOS | 1.0.6 | 84 |
| Android | 10.0.10 | 110 |
Troubleshooting
iOS: Missing Files in Build
- Ensure all
.swiftfiles are in target membership - Clean Build Folder (⌘⇧K)
- Rebuild
Android: Lint Errors
The build.gradle.kts includes:
lint {
abortOnError = false
checkReleaseBuilds = false
}
FCM Token Not Registering
- Check if user is logged in (
ApiClient.isLoggedIn) - Check network connectivity
- Verify JWT has not expired
Logs Not Appearing in Grafana
- Verify
mobile-logsservice is running - Check Loki connectivity
- Query with correct labels:
{job="mobile-logs"}