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.swiftbaseURL property
  • Android: ApiClient.ktBASE_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"}