Skip to main content

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 β†’ baseURL property
  • Android: ApiClient.kt β†’ BASE_URL constant

Firebase​

PlatformConfig File
iOSGoogleService-Info.plist
Androidapp/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​

EndpointMethodAuthDescription
/api/auth/loginPOSTNoUser login
/api/notifications/tokensPOSTJWTRegister FCM token
/api/logsPOSTJWTSend logs
/api/logs/batchPOSTJWTSend batch of logs

Storage​

PlatformStorage Method
iOSUserDefaults
AndroidSharedPreferences

Push Notifications​

Setup​

  1. Firebase is initialized on app launch
  2. App requests notification permission (iOS 10+, Android 13+)
  3. FCM token is fetched
  4. 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​

LevelUse Case
debugDevelopment debugging
infoUser actions, successful operations
warnNon-critical issues
errorFailures, 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​

EventLevelSourceDescription
App launchedinfoAppDelegate/MainActivityApp started
Login attemptinfoLoginView/LoginScreenUser attempting login
Login successfulinfoLoginView/LoginScreenLogin succeeded (includes user_id)
Login failederrorLoginView/LoginScreenLogin failed (includes error)
User logged outinfoContentView/HomeScreenUser tapped logout
Notification permissioninfoAppDelegate/MainActivityPermission granted/denied
FCM token receivedinfoAppDelegate/MainActivityToken fetched (prefix only)
FCM token refreshedinfoFCMServiceToken updated
FCM token registered with backendinfoAppDelegate/MainActivityToken sent to server
FCM token registration failederrorAppDelegate/MainActivityServer registration failed
Push received (foreground)infoAppDelegatePush notification in foreground
Push receivedinfoFCMServicePush notification received
Push tappedinfoAppDelegateUser tapped notification

Building & Deploying​

iOS​

  1. Open VislaGPS.xcodeproj in Xcode
  2. Select target device
  3. Product β†’ Build (⌘B)
  4. For App Store:
    • Product β†’ Archive
    • Validate & Upload

Requirements:

  • Xcode 15+
  • iOS 15.0 minimum deployment target

Android​

  1. Open visla-gps-android/ in Android Studio
  2. Sync Gradle
  3. Run β†’ Run 'app'
  4. 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​

PlatformVersionBuild
iOS1.0.684
Android10.0.10110

Troubleshooting​

iOS: Missing Files in Build​

  1. Ensure all .swift files are in target membership
  2. Clean Build Folder (βŒ˜β‡§K)
  3. Rebuild

Android: Lint Errors​

The build.gradle.kts includes:

lint {
abortOnError = false
checkReleaseBuilds = false
}

FCM Token Not Registering​

  1. Check if user is logged in (ApiClient.isLoggedIn)
  2. Check network connectivity
  3. Verify JWT has not expired

Logs Not Appearing in Grafana​

  1. Verify mobile-logs service is running
  2. Check Loki connectivity
  3. Query with correct labels: {job="mobile-logs"}