Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.bookovia.com/llms.txt

Use this file to discover all available pages before exploring further.

Mobile Integration Guide

This comprehensive guide covers implementing Bookovia telematics in mobile applications across all major platforms, including location tracking, offline support, background processing, and real-time data synchronization.

Platform Overview

Bookovia supports native and cross-platform mobile development:
PlatformSDKLanguageKey Features
iOSNative iOS SDKSwiftCore Location, Background App Refresh, Push Notifications
AndroidNative Android SDKKotlin/JavaForeground Services, WorkManager, FCM
React NativeRN SDKTypeScript/JavaScriptNative modules, Background tasks
FlutterFlutter SDKDartPlatform channels, Isolates

Getting Started

Prerequisites

Before integrating Bookovia in your mobile app:
  • API Keys - Get your API keys from Bookovia Dashboard
  • Platform Setup - Configure development environment for your target platform
  • Permissions - Understand required location and background permissions
  • Testing Devices - Physical devices recommended for location testing

Installation

CocoaPods Installation
# Podfile
pod 'BookoviaTelematics', '~> 1.0.0'
pod install
Swift Package Manager
dependencies: [
    .package(url: "https://github.com/bookovia/ios-sdk.git", from: "1.0.0")
]

Permissions Setup

Location Permissions

Info.plist Configuration
<dict>
    <!-- Always required -->
    <key>NSLocationWhenInUseUsageDescription</key>
    <string>This app needs location access to track your trips and provide safety analytics.</string>
    
    <!-- For background tracking -->
    <key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
    <string>This app needs background location access to track your trips even when the app is not in use.</string>
    
    <!-- Background modes -->
    <key>UIBackgroundModes</key>
    <array>
        <string>location</string>
        <string>background-fetch</string>
    </array>
</dict>
Request Permissions
import CoreLocation
import BookoviaTelematics

class LocationManager: NSObject, CLLocationManagerDelegate {
    private let locationManager = CLLocationManager()
    private let bookovia = BookoviaSDK.shared
    
    func requestPermissions() {
        locationManager.delegate = self
        locationManager.requestWhenInUseAuthorization()
    }
    
    func locationManager(_ manager: CLLocationManager, 
                       didChangeAuthorization status: CLAuthorizationStatus) {
        switch status {
        case .authorizedWhenInUse:
            // Request always authorization for background tracking
            locationManager.requestAlwaysAuthorization()
        case .authorizedAlways:
            // Start background tracking
            bookovia.startBackgroundTracking()
        case .denied:
            // Handle denied permissions
            showPermissionDialog()
        default:
            break
        }
    }
}

Basic Integration

SDK Initialization

import BookoviaTelematics

class AppDelegate: UIResponder, UIApplicationDelegate {
    func application(_ application: UIApplication, 
                    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        
        // Initialize Bookovia SDK
        BookoviaSDK.shared.configure(
            apiKey: "bkv_live_your_api_key",
            environment: .production // or .sandbox
        )
        
        // Set delegate for callbacks
        BookoviaSDK.shared.delegate = self
        
        return true
    }
}

// MARK: - BookoviaSDKDelegate
extension AppDelegate: BookoviaSDKDelegate {
    func bookovia(_ sdk: BookoviaSDK, didStartTrip trip: Trip) {
        print("Trip started: \(trip.id)")
    }
    
    func bookovia(_ sdk: BookoviaSDK, didUpdateLocation location: LocationPoint) {
        // Handle location updates
    }
    
    func bookovia(_ sdk: BookoviaSDK, didDetectSafetyEvent event: SafetyEvent) {
        // Handle safety events
        if event.severity == .critical {
            showSafetyAlert(event)
        }
    }
}

Trip Management

Starting and Stopping Trips

class TripManager {
    private let bookovia = BookoviaSDK.shared
    
    func startTrip() async {
        do {
            let trip = try await bookovia.startTrip(
                metadata: [
                    "driver_name": "John Doe",
                    "vehicle_id": "vehicle_123",
                    "purpose": "delivery"
                ]
            )
            
            print("Trip started: \(trip.id)")
            
            // Update UI
            DispatchQueue.main.async {
                self.updateTripUI(trip: trip)
            }
            
        } catch {
            print("Failed to start trip: \(error)")
            showErrorAlert(error)
        }
    }
    
    func stopTrip() async {
        do {
            let summary = try await bookovia.stopTrip()
            
            print("Trip completed: \(summary.distance) km in \(summary.duration) minutes")
            
            // Show trip summary
            DispatchQueue.main.async {
                self.showTripSummary(summary)
            }
            
        } catch {
            print("Failed to stop trip: \(error)")
        }
    }
}

Background Processing

iOS Background Configuration

import BackgroundTasks

class BackgroundTaskManager {
    static let shared = BackgroundTaskManager()
    private let backgroundTaskIdentifier = "com.yourapp.location-sync"
    
    func registerBackgroundTasks() {
        BGTaskScheduler.shared.register(
            forTaskWithIdentifier: backgroundTaskIdentifier,
            using: nil
        ) { task in
            self.handleLocationSync(task: task as! BGAppRefreshTask)
        }
    }
    
    func scheduleBackgroundSync() {
        let request = BGAppRefreshTaskRequest(identifier: backgroundTaskIdentifier)
        request.earliestBeginDate = Date(timeIntervalSinceNow: 15 * 60) // 15 minutes
        
        try? BGTaskScheduler.shared.submit(request)
    }
    
    private func handleLocationSync(task: BGAppRefreshTask) {
        scheduleBackgroundSync() // Schedule next sync
        
        task.expirationHandler = {
            task.setTaskCompleted(success: false)
        }
        
        // Sync cached location data
        BookoviaSDK.shared.syncCachedData { success in
            task.setTaskCompleted(success: success)
        }
    }
}

Android Foreground Service

import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.Service
import android.content.Intent
import android.os.IBinder
import androidx.core.app.NotificationCompat
import com.bookovia.telematics.BookoviaSDK

class LocationTrackingService : Service() {
    companion object {
        private const val NOTIFICATION_ID = 1
        private const val CHANNEL_ID = "location_tracking"
    }
    
    private lateinit var bookovia: BookoviaSDK
    
    override fun onCreate() {
        super.onCreate()
        bookovia = BookoviaSDK.getInstance(this)
        createNotificationChannel()
    }
    
    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        val notification = createNotification()
        startForeground(NOTIFICATION_ID, notification)
        
        // Start location tracking
        bookovia.startLocationTracking()
        
        return START_STICKY // Restart if killed
    }
    
    override fun onDestroy() {
        super.onDestroy()
        bookovia.stopLocationTracking()
    }
    
    override fun onBind(intent: Intent?): IBinder? = null
    
    private fun createNotificationChannel() {
        val channel = NotificationChannel(
            CHANNEL_ID,
            "Location Tracking",
            NotificationManager.IMPORTANCE_LOW
        ).apply {
            description = "Tracking your location for trip analysis"
            setSound(null, null)
        }
        
        val notificationManager = getSystemService(NotificationManager::class.java)
        notificationManager.createNotificationChannel(channel)
    }
    
    private fun createNotification(): Notification {
        return NotificationCompat.Builder(this, CHANNEL_ID)
            .setContentTitle("Trip in Progress")
            .setContentText("Tracking your location")
            .setSmallIcon(R.drawable.ic_location)
            .setOngoing(true)
            .setSilent(true)
            .build()
    }
}

Offline Support

Data Caching and Sync

import CoreData

class OfflineDataManager {
    lazy var persistentContainer: NSPersistentContainer = {
        let container = NSPersistentContainer(name: "BookoviaCache")
        container.loadPersistentStores { _, error in
            if let error = error {
                fatalError("Core Data error: \(error)")
            }
        }
        return container
    }()
    
    func cacheLocationData(_ locations: [LocationPoint]) {
        let context = persistentContainer.viewContext
        
        for location in locations {
            let cachedLocation = CachedLocation(context: context)
            cachedLocation.latitude = location.latitude
            cachedLocation.longitude = location.longitude
            cachedLocation.timestamp = location.timestamp
            cachedLocation.tripId = location.tripId
            cachedLocation.synced = false
        }
        
        try? context.save()
    }
    
    func syncCachedData() async {
        let context = persistentContainer.newBackgroundContext()
        
        await context.perform {
            let request: NSFetchRequest<CachedLocation> = CachedLocation.fetchRequest()
            request.predicate = NSPredicate(format: "synced == NO")
            request.fetchLimit = 100 // Sync in batches
            
            guard let unsyncedLocations = try? context.fetch(request) else { return }
            
            let locationData = unsyncedLocations.map { cached in
                LocationPoint(
                    latitude: cached.latitude,
                    longitude: cached.longitude,
                    timestamp: cached.timestamp!,
                    tripId: cached.tripId!
                )
            }
            
            // Upload to Bookovia API
            Task {
                do {
                    try await BookoviaSDK.shared.uploadLocationBatch(locationData)
                    
                    // Mark as synced
                    await context.perform {
                        unsyncedLocations.forEach { $0.synced = true }
                        try? context.save()
                    }
                } catch {
                    print("Sync failed: \(error)")
                }
            }
        }
    }
}

Real-time Features

WebSocket Integration

import Foundation
import Starscream

class BookoviaWebSocket: WebSocketDelegate {
    private var socket: WebSocket?
    private let apiKey: String
    
    init(apiKey: String) {
        self.apiKey = apiKey
    }
    
    func connect() {
        guard let url = URL(string: "wss://api.bookovia.com/v1/streaming") else { return }
        
        var request = URLRequest(url: url)
        request.setValue("Bearer \(apiKey)", forHTTPHeaderField: "Authorization")
        
        socket = WebSocket(request: request)
        socket?.delegate = self
        socket?.connect()
    }
    
    func subscribe(to channels: [String], filters: [String: Any] = [:]) {
        let subscription = [
            "type": "subscribe",
            "channels": channels,
            "filters": filters
        ]
        
        if let data = try? JSONSerialization.data(withJSONObject: subscription),
           let string = String(data: data, encoding: .utf8) {
            socket?.write(string: string)
        }
    }
    
    // MARK: - WebSocketDelegate
    
    func didReceive(event: WebSocketEvent, client: WebSocket) {
        switch event {
        case .connected:
            print("WebSocket connected")
            authenticateAndSubscribe()
            
        case .disconnected(let reason, let code):
            print("WebSocket disconnected: \(reason) (\(code))")
            attemptReconnect()
            
        case .text(let text):
            handleMessage(text)
            
        case .error(let error):
            print("WebSocket error: \(error)")
            
        default:
            break
        }
    }
    
    private func authenticateAndSubscribe() {
        // Subscribe to real-time location updates
        subscribe(to: ["locations", "safety_events", "trip_updates"])
    }
    
    private func handleMessage(_ text: String) {
        guard let data = text.data(using: .utf8),
              let json = try? JSONSerialization.jsonObject(with: data) as? [String: Any],
              let type = json["type"] as? String else { return }
        
        switch type {
        case "location_update":
            handleLocationUpdate(json)
        case "safety_event":
            handleSafetyEvent(json)
        case "trip_update":
            handleTripUpdate(json)
        default:
            break
        }
    }
}

UI Implementation

Trip Controls Component

import SwiftUI
import BookoviaTelematics

struct TripControlsView: View {
    @StateObject private var tripManager = TripManager()
    @State private var showingTripSummary = false
    
    var body: some View {
        VStack(spacing: 20) {
            // Trip Status
            tripStatusView
            
            // Control Buttons
            controlButtonsView
            
            // Live Stats
            if tripManager.isTracking {
                liveStatsView
            }
        }
        .padding()
        .sheet(isPresented: $showingTripSummary) {
            TripSummaryView(summary: tripManager.lastTripSummary)
        }
    }
    
    private var tripStatusView: some View {
        HStack {
            Circle()
                .fill(tripManager.isTracking ? Color.green : Color.gray)
                .frame(width: 12, height: 12)
            
            Text(tripManager.isTracking ? "Trip Active" : "No Active Trip")
                .font(.headline)
            
            Spacer()
            
            if tripManager.isTracking {
                Text(tripManager.elapsedTime)
                    .font(.subheadline)
                    .foregroundColor(.secondary)
            }
        }
    }
    
    private var controlButtonsView: some View {
        HStack(spacing: 16) {
            Button(action: {
                if tripManager.isTracking {
                    Task {
                        await tripManager.stopTrip()
                        showingTripSummary = true
                    }
                } else {
                    Task {
                        await tripManager.startTrip()
                    }
                }
            }) {
                HStack {
                    Image(systemName: tripManager.isTracking ? "stop.fill" : "play.fill")
                    Text(tripManager.isTracking ? "Stop Trip" : "Start Trip")
                }
                .frame(maxWidth: .infinity)
                .padding()
                .background(tripManager.isTracking ? Color.red : Color.blue)
                .foregroundColor(.white)
                .cornerRadius(8)
            }
            .disabled(tripManager.isLoading)
        }
    }
    
    private var liveStatsView: some View {
        LazyVGrid(columns: Array(repeating: GridItem(.flexible()), count: 3), spacing: 16) {
            StatCard(title: "Distance", value: "\(tripManager.currentDistance, specifier: "%.1f") km")
            StatCard(title: "Speed", value: "\(tripManager.currentSpeed, specifier: "%.0f") km/h")
            StatCard(title: "Safety Score", value: "\(tripManager.safetyScore, specifier: "%.0f")")
        }
    }
}

struct StatCard: View {
    let title: String
    let value: String
    
    var body: some View {
        VStack {
            Text(title)
                .font(.caption)
                .foregroundColor(.secondary)
            Text(value)
                .font(.headline)
        }
        .padding()
        .background(Color(.systemGray6))
        .cornerRadius(8)
    }
}

Testing and Debugging

Development Testing

import XCTest
import BookoviaTelematics

class BookoviaSDKTests: XCTestCase {
    var sdk: BookoviaSDK!
    
    override func setUpWithError() throws {
        sdk = BookoviaSDK.shared
        sdk.configure(
            apiKey: "bkv_test_your_test_api_key",
            environment: .sandbox
        )
    }
    
    func testTripStartStop() async throws {
        // Start trip
        let trip = try await sdk.startTrip(metadata: ["test": "true"])
        XCTAssertNotNil(trip.id)
        XCTAssertEqual(trip.status, .active)
        
        // Wait a moment
        try await Task.sleep(nanoseconds: 2_000_000_000) // 2 seconds
        
        // Stop trip
        let summary = try await sdk.stopTrip()
        XCTAssertGreaterThan(summary.duration, 0)
        XCTAssertEqual(summary.tripId, trip.id)
    }
    
    func testLocationUpload() async throws {
        let locations = [
            LocationPoint(
                latitude: 40.7128,
                longitude: -74.0060,
                timestamp: Date(),
                accuracy: 5.0
            )
        ]
        
        try await sdk.uploadLocationBatch(locations)
        // Test passes if no exception is thrown
    }
    
    func testOfflineMode() async throws {
        // Simulate offline mode
        sdk.setOfflineMode(true)
        
        let trip = try await sdk.startTrip()
        
        let locations = [
            LocationPoint(
                latitude: 40.7128,
                longitude: -74.0060,
                timestamp: Date()
            )
        ]
        
        // Should cache data instead of uploading
        try await sdk.uploadLocationBatch(locations)
        
        // Go back online
        sdk.setOfflineMode(false)
        
        // Should sync cached data
        try await sdk.syncCachedData()
    }
}

// Simulator testing with mock locations
class LocationSimulator {
    static func simulateTrip() {
        guard let sdk = BookoviaSDK.shared else { return }
        
        let route = [
            (40.7128, -74.0060), // Start
            (40.7138, -74.0050), // Point 1
            (40.7148, -74.0040), // Point 2
            (40.7158, -74.0030), // End
        ]
        
        Task {
            let trip = try await sdk.startTrip()
            
            for (index, coordinate) in route.enumerated() {
                let location = LocationPoint(
                    latitude: coordinate.0,
                    longitude: coordinate.1,
                    timestamp: Date(),
                    speed: 30.0 + Double(index) * 5.0
                )
                
                try await sdk.uploadLocation(location)
                try await Task.sleep(nanoseconds: 1_000_000_000) // 1 second
            }
            
            try await sdk.stopTrip()
        }
    }
}

Best Practices

Performance Optimization

  • Battery Efficiency - Use adaptive location frequency based on movement
  • Network Usage - Batch uploads and compress data when possible
  • Memory Management - Clean up listeners and subscriptions properly
  • Background Processing - Handle app lifecycle changes gracefully

Security Considerations

  • API Key Security - Never hardcode API keys in source code
  • Data Encryption - Use secure storage for cached location data
  • User Privacy - Request minimal necessary permissions
  • Data Anonymization - Consider privacy settings for sensitive data

Error Handling

  • Network Failures - Implement robust offline caching
  • Permission Denials - Provide clear rationale and fallbacks
  • SDK Errors - Log errors for debugging but handle gracefully
  • Data Validation - Validate location data before upload

Testing Strategy

  • Unit Tests - Test SDK integration and data flow
  • Integration Tests - Test end-to-end trip scenarios
  • Device Testing - Test on multiple devices and OS versions
  • Performance Testing - Monitor battery and memory usage

Next Steps

Web Dashboard

Build real-time fleet monitoring dashboards with React and Vue.js

SDK Documentation

Explore detailed SDK documentation for your platform

API Reference

Browse comprehensive API documentation and endpoints

Fleet Management

Learn advanced fleet management and optimization techniques

Ready to integrate Bookovia in your mobile app? Choose your platform SDK and follow the quickstart guide to get up and running in minutes.