๐ Flutter Traccar API
A powerful, feature-rich Flutter package for seamless integration with Traccar GPS tracking servers
๐ Documentation โข ๐ Quick Start โข ๐ก Examples โข ๐ค Contributing
โจ Features
๐ Authentication & Security
๐ฑ Device Management
|
๐ Position Tracking
๐ Advanced Reporting
๐ Real-time WebSocket
|
๐ 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
- Fork the repository
- Clone your fork:
git clone https://github.com/yourusername/flutter_traccar_api.git
- Create a feature branch:
git checkout -b feature/amazing-feature
- Make your changes
- Test your changes:
flutter test
- Commit your changes:
git commit -m 'Add amazing feature'
- Push to the branch:
git push origin feature/amazing-feature
- 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
- ๐ API Documentation
- ๐ฏ Traccar API Reference
- ๐ฑ Flutter Documentation
๐ Support
Need help? We're here for you!
- ๐ฌ GitHub Discussions
- ๐ Issue Tracker
- ๐ง Email Support
- ๐ฌ Discord Community
๐ License
This project is licensed under the MIT License - see the LICENSE file for details.
๐ Acknowledgments
- ๐ Traccar - Open source GPS tracking system
- ๐ฑ Flutter Team - Amazing cross-platform framework
- ๐ฏ Dart Team - Powerful programming language
- ๐ค All our contributors
Made with โค๏ธ by the Flutter community
โญ Star this repo if it helped you! โญ
Libraries
- flutter_traccar_api
- Flutter Traccar API Plugin