๐Ÿš— Flutter Traccar API

pub package License: MIT Flutter Dart

A powerful, feature-rich Flutter package for seamless integration with Traccar GPS tracking servers

๐Ÿ“– Documentation โ€ข ๐Ÿš€ Quick Start โ€ข ๐Ÿ’ก Examples โ€ข ๐Ÿค Contributing


โœจ Features

๐Ÿ” Authentication & Security

  • โœ… Secure login/logout with credential caching
  • โœ… Encrypted storage using flutter_secure_storage
  • โœ… Automatic session management
  • โœ… Token-based authentication

๐Ÿ“ฑ Device Management

  • โœ… Retrieve and manage GPS tracking devices
  • โœ… Real-time device status monitoring
  • โœ… Device configuration and settings
  • โœ… Bulk device operations

๐Ÿ“ Position Tracking

  • โœ… Real-time position updates
  • โœ… Historical position data
  • โœ… Geofence monitoring
  • โœ… Route optimization

๐Ÿ“Š Advanced Reporting

  • โœ… Trip analysis and reports
  • โœ… Stop detection and analysis
  • โœ… Summary statistics
  • โœ… Distance calculations

๐Ÿ”„ Real-time WebSocket

  • โœ… Live device status updates
  • โœ… Real-time position streaming
  • โœ… Event notifications (alarms, geofences)
  • โœ… Automatic reconnection & heartbeat
  • โœ… Connection status monitoring

๐Ÿš€ Performance & Optimization

Feature Description Benefits
๐Ÿง  Intelligent Caching Smart cache management with TTL Faster responses, offline support
โšก Rate Limiting Built-in API rate limiting Prevents server overload
๐Ÿ”„ Request Batching Automatic request optimization Improved performance
๐Ÿ“ฆ Offline Mode Cache-based offline functionality Works without internet
๐Ÿ—๏ธ Type Safety Full OpenAPI-generated models Compile-time error checking

๐Ÿ“ฆ Installation

Add this package to your pubspec.yaml:

dependencies:
  flutter_traccar_api: ^0.1.0
  # Required for secure storage
  flutter_secure_storage: ^9.0.0
  # Required for caching
  shared_preferences: ^2.2.0

Then run:

flutter pub get

๐Ÿ”ง Platform Setup

๐Ÿ“ฑ Android Setup

Add to android/app/src/main/AndroidManifest.xml:

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
๐ŸŽ iOS Setup

No additional setup required for iOS.

๐ŸŒ Web Setup

Ensure your Traccar server supports CORS for web applications.


๐Ÿš€ Quick Start

1๏ธโƒฃ Initialize the API

import 'package:flutter_traccar_api/flutter_traccar_api.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  
  // ๐ŸŽฏ Basic initialization
  await FlutterTraccarApi.initialize('https://your-traccar-server.com');
  
  // ๐Ÿš€ Advanced initialization with performance features
  await FlutterTraccarApi.initialize(
    'https://your-traccar-server.com',
    config: HttpClientConfig(
      enableCaching: true,
      enableRateLimiting: true,
      enableBatching: true,
      enableOfflineMode: true,
      cacheConfig: CacheConfig(
        maxCacheSize: 50 * 1024 * 1024, // 50MB
        defaultTtl: Duration(minutes: 15),
        enableCompression: true,
      ),
      rateLimitConfig: RateLimitConfig(
        requestsPerSecond: 10,
        burstSize: 20,
        enableBackoff: true,
      ),
    ),
  );
  
  runApp(MyApp());
}

2๏ธโƒฃ Authentication

class AuthService {
  final api = FlutterTraccarApi.instance;

  Future<bool> login(String username, String password) async {
    try {
      final user = await api.login(username, password);
      print('โœ… Logged in as: ${user.name}');
      return true;
    } on TraccarApiException catch (e) {
      print('โŒ Login failed: ${e.message}');
      return false;
    }
  }

  Future<void> logout() async {
    await api.logout();
    print('๐Ÿ‘‹ Logged out successfully');
  }

  Future<bool> isLoggedIn() async {
    return await api.isAuthenticated();
  }
}

3๏ธโƒฃ Device Management

class DeviceService {
  final api = FlutterTraccarApi.instance;

  Future<List<Device>> getAllDevices() async {
    try {
      final devices = await api.getDevices();
      print('๐Ÿ“ฑ Found ${devices.length} devices');
      return devices;
    } catch (e) {
      print('โŒ Error fetching devices: $e');
      return [];
    }
  }

  Future<Device?> getDeviceById(int deviceId) async {
    try {
      return await api.getDevice(deviceId);
    } catch (e) {
      print('โŒ Device not found: $e');
      return null;
    }
  }
}

4๏ธโƒฃ Position Tracking

class PositionService {
  final api = FlutterTraccarApi.instance;

  Future<List<Position>> getRecentPositions(int deviceId) async {
    final now = DateTime.now();
    final yesterday = now.subtract(Duration(days: 1));
    
    return await api.getPositions(
      deviceId: deviceId,
      from: yesterday,
      to: now,
    );
  }

  Future<Position?> getLatestPosition(int deviceId) async {
    final positions = await getRecentPositions(deviceId);
    return positions.isNotEmpty ? positions.first : null;
  }
}

5๏ธโƒฃ Real-time WebSocket Updates

class WebSocketService {
  final api = FlutterTraccarApi.instance;

  Future<void> startRealTimeUpdates() async {
    // Connect to WebSocket
    final connected = await api.connectWebSocket();
    if (!connected) {
      print('โŒ Failed to connect to WebSocket');
      return;
    }

    // Listen to real-time device updates
    api.deviceUpdatesStream.listen((devices) {
      print('๐Ÿ“ฑ Device updates: ${devices.length} devices');
    });

    // Listen to real-time position updates
    api.positionUpdatesStream.listen((positions) {
      print('๐Ÿ“ Position updates: ${positions.length} positions');
    });

    // Listen to real-time events (alarms, geofences, etc.)
    api.eventUpdatesStream.listen((events) {
      print('๐Ÿšจ Events: ${events.length} events');
    });

    // Monitor connection status
    api.webSocketStatusStream.listen((status) {
      print('๐Ÿ”— WebSocket status: ${status.name}');
    });
  }

  Future<void> stopRealTimeUpdates() async {
    await api.disconnectWebSocket();
    print('๐Ÿ”Œ WebSocket disconnected');
  }
}

๐Ÿ’ก Examples

๐ŸŽฏ Complete Flutter App Example

import 'package:flutter/material.dart';
import 'package:flutter_traccar_api/flutter_traccar_api.dart';

class TraccarDashboard extends StatefulWidget {
  @override
  _TraccarDashboardState createState() => _TraccarDashboardState();
}

class _TraccarDashboardState extends State<TraccarDashboard> {
  final api = FlutterTraccarApi.instance;
  List<Device> devices = [];
  bool isLoading = true;

  @override
  void initState() {
    super.initState();
    _loadDevices();
  }

  Future<void> _loadDevices() async {
    try {
      final fetchedDevices = await api.getDevices();
      setState(() {
        devices = fetchedDevices;
        isLoading = false;
      });
    } catch (e) {
      setState(() => isLoading = false);
      _showError('Failed to load devices: $e');
    }
  }

  void _showError(String message) {
    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(content: Text(message), backgroundColor: Colors.red),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('๐Ÿš— Traccar Dashboard'),
        actions: [
          IconButton(
            icon: Icon(Icons.refresh),
            onPressed: _loadDevices,
          ),
        ],
      ),
      body: isLoading
          ? Center(child: CircularProgressIndicator())
          : devices.isEmpty
              ? Center(
                  child: Column(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: [
                      Icon(Icons.devices, size: 64, color: Colors.grey),
                      SizedBox(height: 16),
                      Text('No devices found'),
                    ],
                  ),
                )
              : ListView.builder(
                  itemCount: devices.length,
                  itemBuilder: (context, index) {
                    final device = devices[index];
                    return DeviceCard(device: device);
                  },
                ),
    );
  }
}

class DeviceCard extends StatelessWidget {
  final Device device;

  const DeviceCard({Key? key, required this.device}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Card(
      margin: EdgeInsets.all(8),
      child: ListTile(
        leading: CircleAvatar(
          backgroundColor: device.status == 'online' ? Colors.green : Colors.red,
          child: Icon(Icons.gps_fixed, color: Colors.white),
        ),
        title: Text(device.name ?? 'Unknown Device'),
        subtitle: Text('ID: ${device.id} โ€ข Status: ${device.status}'),
        trailing: Icon(Icons.arrow_forward_ios),
        onTap: () {
          Navigator.push(
            context,
            MaterialPageRoute(
              builder: (context) => DeviceDetailPage(device: device),
            ),
          );
        },
      ),
    );
  }
}

๐Ÿ“Š Advanced Reporting Example

class ReportService {
  final api = FlutterTraccarApi.instance;

  Future<Map<String, dynamic>> generateComprehensiveReport(
    List<int> deviceIds,
    DateTime from,
    DateTime to,
  ) async {
    try {
      // ๐Ÿš— Get trip reports
      final trips = await api.getTripReports(
        deviceIds: deviceIds,
        from: from,
        to: to,
      );

      // ๐Ÿ“Š Get summary reports
      final summaries = await api.getSummaryReports(
        deviceIds: deviceIds,
        from: from,
        to: to,
      );

      // ๐Ÿ›‘ Get stop reports
      final stops = await api.getStopReports(
        deviceIds: deviceIds,
        from: from,
        to: to,
      );

      return {
        'trips': trips,
        'summaries': summaries,
        'stops': stops,
        'totalDistance': summaries.fold<double>(
          0,
          (sum, summary) => sum + (summary.distance ?? 0),
        ),
        'totalDuration': trips.fold<Duration>(
          Duration.zero,
          (sum, trip) => sum + (trip.duration ?? Duration.zero),
        ),
      };
    } catch (e) {
      throw Exception('Failed to generate report: $e');
    }
  }
}

๐Ÿ”„ Real-time WebSocket Updates

The package provides powerful WebSocket functionality for real-time updates without polling:

๐Ÿš€ Basic WebSocket Usage

class RealTimeTracker {
  final api = FlutterTraccarApi.instance;
  late StreamSubscription<List<Device>> _deviceSubscription;
  late StreamSubscription<List<Position>> _positionSubscription;
  late StreamSubscription<List<Event>> _eventSubscription;
  late StreamSubscription<WebSocketStatus> _statusSubscription;

  Future<void> startRealTimeTracking() async {
    // Connect to WebSocket
    final connected = await api.connectWebSocket();
    if (!connected) {
      throw Exception('Failed to connect to WebSocket');
    }

    // Listen to real-time device updates
    _deviceSubscription = api.deviceUpdatesStream.listen(
      (devices) {
        print('๐Ÿ“ฑ Received ${devices.length} device updates');
        // Handle device updates (status changes, etc.)
      },
      onError: (error) => print('โŒ Device stream error: $error'),
    );

    // Listen to real-time position updates
    _positionSubscription = api.positionUpdatesStream.listen(
      (positions) {
        print('๐Ÿ“ Received ${positions.length} position updates');
        // Handle position updates (location changes)
      },
      onError: (error) => print('โŒ Position stream error: $error'),
    );

    // Listen to real-time events
    _eventSubscription = api.eventUpdatesStream.listen(
      (events) {
        print('๐Ÿšจ Received ${events.length} events');
        // Handle events (alarms, geofence violations, etc.)
      },
      onError: (error) => print('โŒ Event stream error: $error'),
    );

    // Monitor WebSocket connection status
    _statusSubscription = api.webSocketStatusStream.listen(
      (status) {
        switch (status) {
          case WebSocketStatus.connected:
            print('โœ… WebSocket connected');
            break;
          case WebSocketStatus.disconnected:
            print('โŒ WebSocket disconnected');
            break;
          case WebSocketStatus.connecting:
            print('๐Ÿ”„ WebSocket connecting...');
            break;
          case WebSocketStatus.reconnecting:
            print('๐Ÿ”„ WebSocket reconnecting...');
            break;
          case WebSocketStatus.error:
            print('โŒ WebSocket error');
            break;
        }
      },
    );
  }

  Future<void> stopRealTimeTracking() async {
    // Cancel all subscriptions
    await _deviceSubscription.cancel();
    await _positionSubscription.cancel();
    await _eventSubscription.cancel();
    await _statusSubscription.cancel();
    
    // Disconnect WebSocket
    await api.disconnectWebSocket();
  }

  bool get isConnected => api.isWebSocketConnected;
}

๐ŸŽฏ Advanced WebSocket Configuration

// Initialize with custom WebSocket configuration
await FlutterTraccarApi.initialize(
  'https://your-traccar-server.com',
  config: HttpClientConfig(
    webSocketConfig: WebSocketConfig(
      enableAutoReconnect: true,
      maxReconnectAttempts: 5,
      reconnectInterval: Duration(seconds: 5),
      heartbeatInterval: Duration(seconds: 30),
    ),
  ),
);

๐Ÿ“ฑ Flutter Widget Integration

class LiveTrackingWidget extends StatefulWidget {
  @override
  _LiveTrackingWidgetState createState() => _LiveTrackingWidgetState();
}

class _LiveTrackingWidgetState extends State<LiveTrackingWidget> {
  final api = FlutterTraccarApi.instance;
  List<Device> devices = [];
  List<Position> positions = [];
  WebSocketStatus connectionStatus = WebSocketStatus.disconnected;

  @override
  void initState() {
    super.initState();
    _initializeWebSocket();
  }

  Future<void> _initializeWebSocket() async {
    // Connect to WebSocket
    await api.connectWebSocket();

    // Listen to streams
    api.deviceUpdatesStream.listen((updatedDevices) {
      setState(() => devices = updatedDevices);
    });

    api.positionUpdatesStream.listen((updatedPositions) {
      setState(() => positions = updatedPositions);
    });

    api.webSocketStatusStream.listen((status) {
      setState(() => connectionStatus = status);
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Live Tracking'),
        actions: [
          Icon(
            connectionStatus == WebSocketStatus.connected
                ? Icons.wifi
                : Icons.wifi_off,
            color: connectionStatus == WebSocketStatus.connected
                ? Colors.green
                : Colors.red,
          ),
        ],
      ),
      body: Column(
        children: [
          // Connection status
          Container(
            padding: EdgeInsets.all(8),
            color: connectionStatus == WebSocketStatus.connected
                ? Colors.green.withOpacity(0.1)
                : Colors.red.withOpacity(0.1),
            child: Row(
              children: [
                Icon(
                  connectionStatus == WebSocketStatus.connected
                      ? Icons.check_circle
                      : Icons.error,
                  color: connectionStatus == WebSocketStatus.connected
                      ? Colors.green
                      : Colors.red,
                ),
                SizedBox(width: 8),
                Text('Status: ${connectionStatus.name}'),
              ],
            ),
          ),
          // Live device list
          Expanded(
            child: ListView.builder(
              itemCount: devices.length,
              itemBuilder: (context, index) {
                final device = devices[index];
                final position = positions
                    .where((p) => p.deviceId == device.id)
                    .lastOrNull;
                
                return ListTile(
                  leading: CircleAvatar(
                    backgroundColor: device.status == 'online'
                        ? Colors.green
                        : Colors.grey,
                    child: Icon(Icons.device_hub, color: Colors.white),
                  ),
                  title: Text(device.name ?? 'Unknown Device'),
                  subtitle: position != null
                      ? Text(
                          'Lat: ${position.latitude?.toStringAsFixed(6)}, '
                          'Lng: ${position.longitude?.toStringAsFixed(6)}\n'
                          'Speed: ${position.speed?.toStringAsFixed(1)} km/h',
                        )
                      : Text('No position data'),
                  trailing: Text(
                    position?.deviceTime ?? 'No update',
                    style: TextStyle(fontSize: 12),
                  ),
                );
              },
            ),
          ),
        ],
      ),
    );
  }

  @override
  void dispose() {
    api.disconnectWebSocket();
    super.dispose();
  }
}

๐ŸŽ›๏ธ Advanced Configuration

๐Ÿง  Cache Management

// Get cache statistics
final stats = await api.getCacheStats();
print('๐Ÿ“Š Cache Stats:');
print('  Size: ${(stats.totalSize / 1024 / 1024).toStringAsFixed(2)} MB');
print('  Hit Rate: ${stats.hitRate.toStringAsFixed(1)}%');
print('  Entries: ${stats.entryCount}');

// Clear specific caches
await api.invalidateDeviceCache();
await api.invalidatePositionCache();

// Clear all cache
await api.clearCache();

โšก Rate Limiting

// Check rate limit status
final status = api.getRateLimitStatus();
if (status != null) {
  print('โšก Rate Limit Status:');
  print('  Remaining: ${status.remainingRequests}');
  print('  Reset: ${status.resetTime}');
  print('  Limit: ${status.requestLimit}');
}

// Reset rate limiter
api.resetRateLimit();

๐Ÿ”„ Request Batching

// Get batching statistics
final batchStats = api.getBatchingStats();
if (batchStats != null) {
  print('๐Ÿ”„ Batch Stats:');
  print('  Total Batches: ${batchStats.totalBatches}');
  print('  Avg Size: ${batchStats.averageBatchSize.toStringAsFixed(1)}');
  print('  Pending: ${batchStats.pendingRequests}');
}

// Flush pending batches
await api.flushAllBatches();

๐Ÿ› ๏ธ API Reference

๐Ÿ” Authentication Methods
// Login with credentials
Future<User> login(String email, String password);

// Logout and clear session
Future<void> logout();

// Check authentication status
Future<bool> isAuthenticated();

// Get current username
Future<String?> currentUsername();

// Check for cached credentials
Future<bool> hasCachedCredentials();
๐Ÿ“ฑ Device Management
// Get all devices
Future<List<Device>> getDevices();

// Get specific device
Future<Device> getDevice(int deviceId);

// Get device with caching
Future<List<Device>> getDevicesCached();
๐Ÿ“ Position Tracking
// Get positions with filters
Future<List<Position>> getPositions({
  int? deviceId,
  List<int>? deviceIds,
  DateTime? from,
  DateTime? to,
});

// Get latest positions
Future<List<Position>> getLatestPositions(List<int> deviceIds);
๐Ÿ“Š Reporting
// Trip reports
Future<List<TripReport>> getTripReports({
  required List<int> deviceIds,
  required DateTime from,
  required DateTime to,
});

// Summary reports
Future<List<SummaryReport>> getSummaryReports({
  required List<int> deviceIds,
  required DateTime from,
  required DateTime to,
});

// Stop reports
Future<List<StopReport>> getStopReports({
  required List<int> deviceIds,
  required DateTime from,
  required DateTime to,
});

// Distance reports
Future<List<ReportDistance>> getDistanceReports({
  required List<int> deviceIds,
  required DateTime from,
  required DateTime to,
});

๐Ÿ—๏ธ Architecture

flutter_traccar_api/
โ”œโ”€โ”€ ๐Ÿ“ lib/
โ”‚   โ”œโ”€โ”€ ๐Ÿ“„ flutter_traccar_api.dart          # Public API
โ”‚   โ””โ”€โ”€ ๐Ÿ“ src/
โ”‚       โ”œโ”€โ”€ ๐Ÿ“ models/                       # Data models
โ”‚       โ”‚   โ”œโ”€โ”€ ๐Ÿ“„ device.dart
โ”‚       โ”‚   โ”œโ”€โ”€ ๐Ÿ“„ position.dart
โ”‚       โ”‚   โ”œโ”€โ”€ ๐Ÿ“„ user.dart
โ”‚       โ”‚   โ””โ”€โ”€ ๐Ÿ“„ ...
โ”‚       โ”œโ”€โ”€ ๐Ÿ“ services/                     # Core services
โ”‚       โ”‚   โ”œโ”€โ”€ ๐Ÿ“„ auth_manager.dart         # Authentication
โ”‚       โ”‚   โ”œโ”€โ”€ ๐Ÿ“„ http_service.dart         # HTTP client
โ”‚       โ”‚   โ”œโ”€โ”€ ๐Ÿ“„ cache_manager.dart        # Caching
โ”‚       โ”‚   โ”œโ”€โ”€ ๐Ÿ“„ rate_limiter.dart         # Rate limiting
โ”‚       โ”‚   โ””โ”€โ”€ ๐Ÿ“„ request_batcher.dart      # Request batching
โ”‚       โ”œโ”€โ”€ ๐Ÿ“ exceptions/                   # Error handling
โ”‚       โ””โ”€โ”€ ๐Ÿ“ utils/                        # Utilities
โ”œโ”€โ”€ ๐Ÿ“ example/                              # Example app
โ””โ”€โ”€ ๐Ÿ“ test/                                 # Unit tests

๐Ÿงช Testing

Run the test suite:

# Run all tests
flutter test

# Run with coverage
flutter test --coverage

# Run specific test file
flutter test test/services/auth_manager_test.dart

๐ŸŽฏ Test Coverage

  • โœ… Authentication flows
  • โœ… Device management
  • โœ… Position tracking
  • โœ… Report generation
  • โœ… Error handling
  • โœ… Cache management
  • โœ… Rate limiting
  • โœ… Request batching

๐Ÿ“‹ Requirements

Component Version
๐ŸŽฏ Dart SDK >=3.0.0 <4.0.0
๐Ÿ“ฑ Flutter >=3.0.0
๐Ÿ–ฅ๏ธ Traccar Server >=5.0

๐Ÿ“ฆ Dependencies

dependencies:
  dio: ^5.3.0                    # HTTP client
  flutter_secure_storage: ^9.0.0 # Secure storage
  shared_preferences: ^2.2.0     # Local storage
  crypto: ^3.0.3                 # Cryptographic functions
  intl: ^0.18.0                  # Internationalization

๐Ÿค Contributing

We welcome contributions! Here's how you can help:

๐Ÿš€ Getting Started

  1. Fork the repository
  2. Clone your fork: git clone https://github.com/yourusername/flutter_traccar_api.git
  3. Create a feature branch: git checkout -b feature/amazing-feature
  4. Make your changes
  5. Test your changes: flutter test
  6. Commit your changes: git commit -m 'Add amazing feature'
  7. Push to the branch: git push origin feature/amazing-feature
  8. Open a Pull Request

๐Ÿ“ Development Guidelines

  • Follow Effective Dart guidelines
  • Write tests for new features
  • Update documentation for API changes
  • Use conventional commit messages

๐Ÿ› Reporting Issues

Found a bug? Please open an issue with:

  • ๐Ÿ“ฑ Flutter version
  • ๐Ÿ“ฆ Package version
  • ๐Ÿ” Steps to reproduce
  • ๐Ÿ“‹ Expected vs actual behavior

๐Ÿ“š Documentation


๐Ÿ†˜ Support

Need help? We're here for you!


๐Ÿ“„ License

This project is licensed under the MIT License - see the LICENSE file for details.


๐Ÿ™ Acknowledgments


Made with โค๏ธ by the Flutter community

โญ Star this repo if it helped you! โญ

Libraries

flutter_traccar_api
Flutter Traccar API Plugin