A comprehensive Flutter plugin for GPS location tracking with VietmapTrackingSDK integration, featuring advanced background support and speed alerts.
- 🎯 GPS Location Tracking - Continuous location tracking with configurable accuracy
- 📡 VietmapTrackingSDK Integration - Native SDK integration for iOS and Android
- 🔋 Background Tracking - Continue tracking even when app is in background
- ⚡ Speed Alert System - Real-time speed monitoring
- 🎨 Pre-configured Presets - Navigation, Fitness, General, and Battery Saver modes
- 📍 Permission Handling - Automatic location permission management
- 📊 Event Streams - Real-time location and tracking status updates
- 💾 Session Management - Track session statistics and history
- 🔌 Cross-Platform - Works on both iOS (11.0+) and Android (API 21+)
Add this to your package's pubspec.yaml file:
dependencies:
vietmap_tracking_plugin: ^1.0.0Then run:
flutter pub getAdd the following permissions to your AndroidManifest.xml:
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION" />
</manifest>Add the following keys to your Info.plist:
<key>NSLocationWhenInUseUsageDescription</key>
<string>This app needs access to location when in use.</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>This app needs access to location for background tracking.</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>This app needs access to location for background tracking.</string>
<key>UIBackgroundModes</key>
<array>
<string>location</string>
</array>import 'package:vietmap_tracking_plugin/vietmap_tracking_plugin.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
final controller = VietmapTrackingController.instance;
// Configure with your API key
await controller.configure(
'YOUR_API_KEY',
baseURL: 'https://api.vietmap.vn',
);
runApp(MyApp());
}// Use a pre-configured preset
final config = TrackingPresets.navigation();
// Or create custom configuration
final config = LocationTrackingConfig(
intervalMs: 5000,
distanceFilter: 10.0,
accuracy: LocationAccuracy.high,
backgroundMode: true,
notificationTitle: 'Tracking Active',
notificationMessage: 'Your location is being tracked',
);
// Start tracking
await controller.startTracking(config);controller.onLocationUpdate.listen((LocationData location) {
print('Lat: ${location.latitude}, Lng: ${location.longitude}');
print('Speed: ${location.speed} m/s');
print('Accuracy: ${location.accuracy} meters');
});controller.onTrackingStatusChanged.listen((TrackingStatus status) {
print('Is Tracking: ${status.isTracking}');
print('Duration: ${status.duration}');
});await controller.stopTracking();Main controller for managing tracking operations.
// Configure SDK
Future<bool> configure(String apiKey, {String? baseURL})
// Configure Alert API for speed monitoring
Future<bool> configureAlertAPI(String apiKey, String apiID)// Request location permissions
Future<PermissionResult> requestLocationPermissions()
// Check if permissions are granted
Future<PermissionResult> hasLocationPermissions()
// Request always (background) permissions
Future<String> requestAlwaysLocationPermissions()// Start tracking with configuration
Future<bool> startTracking(LocationTrackingConfig config)
// Stop tracking
Future<bool> stopTracking()
// Get current location (one-time fetch)
Future<LocationData> getCurrentLocation()
// Check if tracking is active
Future<bool> isTrackingActive()
// Get detailed tracking status
Future<TrackingStatus> getTrackingStatus()
// Update configuration while tracking
Future<bool> updateTrackingConfig(LocationTrackingConfig config)// Location update stream
Stream<LocationData> onLocationUpdate
// Tracking status stream
Stream<TrackingStatus> onTrackingStatusChangedConfiguration for location tracking:
LocationTrackingConfig({
required int intervalMs, // Update interval in milliseconds
required double distanceFilter, // Minimum distance in meters
required LocationAccuracy accuracy, // GPS accuracy level
required bool backgroundMode, // Enable background tracking
String? notificationTitle, // Android notification title
String? notificationMessage, // Android notification message
})GPS location data:
LocationData({
required double latitude,
required double longitude,
required double altitude,
required double accuracy,
required double speed,
required double bearing,
required int timestamp,
})Tracking session status:
TrackingStatus({
required bool isTracking,
int? lastLocationUpdate,
required int trackingDuration,
})Location permission status:
PermissionResult({
required bool granted,
required PermissionStatus status,
required bool fineLocation,
required bool coarseLocation,
required bool backgroundLocation,
})High accuracy, frequent updates (3s interval, 5m distance filter):
final config = TrackingPresets.navigation();Balanced accuracy and battery (5s interval, 10m distance filter):
final config = TrackingPresets.fitness();Medium accuracy, standard updates (10s interval, 15m distance filter):
final config = TrackingPresets.general();Lower accuracy, less frequent (30s interval, 50m distance filter):
final config = TrackingPresets.batterySaver();// Calculate distance between coordinates (Haversine formula)
double calculateDistance(double lat1, double lon1, double lat2, double lon2)
// Calculate distance between LocationData objects
double distanceBetween(LocationData loc1, LocationData loc2)
// Convert speed units
double metersPerSecondToKmh(double metersPerSecond)
double kmhToMetersPerSecond(double kmh)
// Format coordinates
String formatCoordinates(double latitude, double longitude)
// Check if location is within radius
bool isWithinRadius(LocationData location, double targetLat, double targetLon, double radiusMeters)See the example directory for a complete working example.
import 'package:flutter/material.dart';
import 'package:vietmap_tracking_plugin/vietmap_tracking_plugin.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
final controller = VietmapTrackingController.instance;
LocationData? currentLocation;
@override
void initState() {
super.initState();
_initialize();
_setupListeners();
}
Future<void> _initialize() async {
await controller.configure('YOUR_API_KEY');
}
void _setupListeners() {
controller.onLocationUpdate.listen((location) {
setState(() => currentLocation = location);
});
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('Vietmap Tracking')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('Latitude: ${currentLocation?.latitude ?? "N/A"}'),
Text('Longitude: ${currentLocation?.longitude ?? "N/A"}'),
ElevatedButton(
onPressed: () async {
final config = TrackingPresets.navigation();
await controller.startTracking(config);
},
child: Text('Start Tracking'),
),
ElevatedButton(
onPressed: () => controller.stopTracking(),
child: Text('Stop Tracking'),
),
],
),
),
),
);
}
}final customConfig = LocationTrackingConfig(
intervalMs: 2000, // Update every 2 seconds
distanceFilter: 5.0, // Minimum 5 meters movement
accuracy: LocationAccuracy.high,
backgroundMode: true,
notificationTitle: 'Delivery Tracking',
notificationMessage: 'Tracking your delivery route',
);
await controller.startTracking(customConfig);// Start with battery saver
await controller.startTracking(TrackingPresets.batterySaver());
// Switch to navigation mode
await controller.updateTrackingConfig(TrackingPresets.navigation());// Check current permissions
final permissionResult = await controller.hasLocationPermissions();
if (!permissionResult.granted) {
// Request permissions
final result = await controller.requestLocationPermissions();
if (!result.granted) {
// Show error to user
print('Location permission denied');
return;
}
}
// Request background permission for iOS
if (Platform.isIOS) {
final alwaysPermission = await controller.requestAlwaysLocationPermissions();
print('Always permission: $alwaysPermission');
}final List<LocationData> locations = [];
double totalDistance = 0.0;
controller.onLocationUpdate.listen((location) {
if (locations.isNotEmpty) {
final distance = LocationUtils.distanceBetween(
locations.last,
location,
);
totalDistance += distance;
}
locations.add(location);
print('Total distance: ${totalDistance / 1000} km');
});Issue: Background tracking stops after some time
- Ensure
FOREGROUND_SERVICEandFOREGROUND_SERVICE_LOCATIONpermissions are declared - Add battery optimization exemption for your app
Issue: Location permission denied
- Check that all required permissions are in
AndroidManifest.xml - For Android 10+, ensure
ACCESS_BACKGROUND_LOCATIONis declared
Issue: Location updates stop in background
- Ensure
UIBackgroundModesincludeslocationinInfo.plist - Request "Always" location permission
Issue: Permission dialog not showing
- Make sure all required keys are in
Info.plist - Check that you're calling permission requests from main thread
Contributions are welcome! Please feel free to submit a Pull Request.
This project is licensed under the MIT License - see the LICENSE file for details.
For issues, questions, or feature requests, please file an issue on GitHub.
See CHANGELOG.md for version history and updates.