flutter_map_background_location 1.1.0
flutter_map_background_location: ^1.1.0 copied to clipboard
A Flutter plugin for tracking location in both foreground and background modes, similar to flutter_background_geolocation.
example/lib/main.dart
import 'package:flutter/material.dart';
import 'package:flutter_map_background_location/background_location_tracker_library.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Background Location Tracker Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue),
useMaterial3: true,
),
home: const LocationTrackerDemo(),
);
}
}
class LocationTrackerDemo extends StatefulWidget {
const LocationTrackerDemo({super.key});
@override
State<LocationTrackerDemo> createState() => _LocationTrackerDemoState();
}
class _LocationTrackerDemoState extends State<LocationTrackerDemo> {
final BackgroundLocationTracker _locationTracker =
BackgroundLocationTracker();
LocationData? _currentLocation;
LocationPermissionStatus _permissionStatus =
LocationPermissionStatus.notDetermined;
bool _isServiceEnabled = false;
bool _isTracking = false;
final List<String> _locationHistory = [];
final List<String> _errors = [];
@override
void initState() {
super.initState();
_initializeLocationTracking();
}
Future<void> _initializeLocationTracking() async {
// Check service status
final serviceEnabled = await _locationTracker.isLocationServiceEnabled();
setState(() {
_isServiceEnabled = serviceEnabled;
});
// Check permission
final permission = await _locationTracker.checkPermission();
setState(() {
_permissionStatus = permission;
});
// Listen to location updates
_locationTracker.onLocationUpdate.listen((location) {
setState(() {
_currentLocation = location;
_locationHistory.insert(
0,
'${location.timestamp.toLocal()}: ${location.latitude.toStringAsFixed(6)}, ${location.longitude.toStringAsFixed(6)}',
);
if (_locationHistory.length > 20) {
_locationHistory.removeLast();
}
});
});
// Listen to errors
_locationTracker.onError.listen((error) {
setState(() {
_errors.insert(0, '${DateTime.now().toLocal()}: $error');
if (_errors.length > 10) {
_errors.removeLast();
}
});
});
}
Future<void> _requestPermission() async {
final permission = await _locationTracker.requestPermission();
setState(() {
_permissionStatus = permission;
});
}
Future<void> _requestBackgroundPermission() async {
final permission = await _locationTracker.requestPermission(
requestBackgroundPermission: true,
);
setState(() {
_permissionStatus = permission;
});
}
Future<void> _getCurrentLocation() async {
final location = await _locationTracker.getCurrentLocation();
if (location != null) {
setState(() {
_currentLocation = location;
});
}
}
Future<void> _startTracking({bool background = false}) async {
final settings = LocationSettings(
accuracy: LocationAccuracy.high,
distanceFilter: 10.0,
timeInterval: 5000,
enableBackgroundTracking: background,
showBackgroundNotification: background,
notificationTitle: 'Location Tracking Demo',
notificationText: 'Məkanınız izlənilir',
allowMockLocations: false,
);
final success = await _locationTracker.startTracking(settings);
setState(() {
_isTracking = success;
});
}
Future<void> _stopTracking() async {
await _locationTracker.stopTracking();
setState(() {
_isTracking = false;
});
}
@override
void dispose() {
_locationTracker.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Background Location Tracker'),
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
),
body: SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
// Status Card
Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Status',
style: Theme.of(context).textTheme.titleLarge,
),
const SizedBox(height: 8),
_buildStatusRow(
'Location Service',
_isServiceEnabled ? 'Enabled' : 'Disabled',
_isServiceEnabled ? Colors.green : Colors.red,
),
_buildStatusRow(
'Permission',
_permissionStatus.name,
_permissionStatus.isGranted ? Colors.green : Colors.red,
),
_buildStatusRow(
'Tracking',
_isTracking ? 'Active' : 'Inactive',
_isTracking ? Colors.green : Colors.grey,
),
],
),
),
),
const SizedBox(height: 16),
// Current Location Card
if (_currentLocation != null)
Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Current Location',
style: Theme.of(context).textTheme.titleLarge,
),
const SizedBox(height: 8),
_buildInfoRow('Latitude',
_currentLocation!.latitude.toStringAsFixed(6)),
_buildInfoRow('Longitude',
_currentLocation!.longitude.toStringAsFixed(6)),
_buildInfoRow('Accuracy',
'${_currentLocation!.accuracy.toStringAsFixed(2)}m'),
if (_currentLocation!.altitude != null)
_buildInfoRow('Altitude',
'${_currentLocation!.altitude!.toStringAsFixed(2)}m'),
if (_currentLocation!.speed != null)
_buildInfoRow('Speed',
'${_currentLocation!.speed!.toStringAsFixed(2)}m/s'),
if (_currentLocation!.heading != null)
_buildInfoRow('Heading',
'${_currentLocation!.heading!.toStringAsFixed(2)}°'),
_buildInfoRow('Timestamp',
_currentLocation!.timestamp.toLocal().toString()),
_buildInfoRow('Mock Location',
_currentLocation!.isMocked ? 'Yes' : 'No'),
],
),
),
),
const SizedBox(height: 16),
// Permission Buttons
Text(
'Permissions',
style: Theme.of(context).textTheme.titleMedium,
),
const SizedBox(height: 8),
ElevatedButton.icon(
onPressed: _requestPermission,
icon: const Icon(Icons.location_on),
label: const Text('Request Foreground Permission'),
),
const SizedBox(height: 8),
ElevatedButton.icon(
onPressed: _requestBackgroundPermission,
icon: const Icon(Icons.location_searching),
label: const Text('Request Background Permission'),
),
const SizedBox(height: 8),
ElevatedButton.icon(
onPressed: () => _locationTracker.openAppSettings(),
icon: const Icon(Icons.settings),
label: const Text('Open App Settings'),
),
const SizedBox(height: 16),
// Tracking Buttons
Text(
'Tracking',
style: Theme.of(context).textTheme.titleMedium,
),
const SizedBox(height: 8),
ElevatedButton.icon(
onPressed: _getCurrentLocation,
icon: const Icon(Icons.my_location),
label: const Text('Get Current Location'),
),
const SizedBox(height: 8),
ElevatedButton.icon(
onPressed: _isTracking ? null : () => _startTracking(),
icon: const Icon(Icons.play_arrow),
label: const Text('Start Foreground Tracking'),
),
const SizedBox(height: 8),
ElevatedButton.icon(
onPressed: _isTracking
? null
: () => _startTracking(background: true),
icon: const Icon(Icons.play_circle_filled),
label: const Text('Start Background Tracking'),
),
const SizedBox(height: 8),
ElevatedButton.icon(
onPressed: _isTracking ? _stopTracking : null,
icon: const Icon(Icons.stop),
label: const Text('Stop Tracking'),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.red,
foregroundColor: Colors.white,
),
),
const SizedBox(height: 16),
// Location History
if (_locationHistory.isNotEmpty) ...[
Text(
'Location History',
style: Theme.of(context).textTheme.titleMedium,
),
const SizedBox(height: 8),
Card(
child: Container(
constraints: const BoxConstraints(maxHeight: 200),
child: ListView.builder(
shrinkWrap: true,
itemCount: _locationHistory.length,
itemBuilder: (context, index) {
return ListTile(
dense: true,
leading: const Icon(Icons.location_pin, size: 16),
title: Text(
_locationHistory[index],
style: const TextStyle(fontSize: 12),
),
);
},
),
),
),
],
const SizedBox(height: 16),
// Errors
if (_errors.isNotEmpty) ...[
Text(
'Errors',
style: Theme.of(context).textTheme.titleMedium,
),
const SizedBox(height: 8),
Card(
color: Colors.red.shade50,
child: Container(
constraints: const BoxConstraints(maxHeight: 150),
child: ListView.builder(
shrinkWrap: true,
itemCount: _errors.length,
itemBuilder: (context, index) {
return ListTile(
dense: true,
leading: const Icon(Icons.error, size: 16, color: Colors.red),
title: Text(
_errors[index],
style: const TextStyle(fontSize: 12, color: Colors.red),
),
);
},
),
),
),
],
],
),
),
);
}
Widget _buildStatusRow(String label, String value, Color color) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 4),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(label),
Container(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 4),
decoration: BoxDecoration(
color: color.withValues(alpha: 0.2),
borderRadius: BorderRadius.circular(12),
),
child: Text(
value,
style: TextStyle(
color: color,
fontWeight: FontWeight.bold,
),
),
),
],
),
);
}
Widget _buildInfoRow(String label, String value) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 4),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(label, style: const TextStyle(fontWeight: FontWeight.w500)),
Text(value),
],
),
);
}
}