flutter_background_service
flutter_background_service copied to clipboard
Kill background services when closes app completely
I need my service to keep sending events in the background, but when it closes completely it also closes the services, I have done everything, but I can't get it, can you give me any idea of what is wrong here?
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:geolocator/geolocator.dart';
import 'package:http/http.dart' as http;
import 'package:logging/logging.dart';
import 'dart:convert';
import 'package:flutter_background_service/flutter_background_service.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
final logger = Logger('LocationApp');
Future<void> initializeService() async {
final service = FlutterBackgroundService();
// Verifica si el servicio ya está en ejecución
if (await service.isRunning()) {
return;
}
// Inicializa el plugin de notificaciones
final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
FlutterLocalNotificationsPlugin();
// Configura el canal de notificación para Android
const AndroidNotificationChannel channel = AndroidNotificationChannel(
'my_foreground',
'Rastreando ubicación',
description: 'Notificaciones del servicio de rastreo de ubicación',
importance: Importance.high,
);
// Crea el canal de notificación
await flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin>()
?.createNotificationChannel(channel);
await service.configure(
androidConfiguration: AndroidConfiguration(
onStart: onStart,
autoStart: false,
isForegroundMode: true,
notificationChannelId: 'my_foreground',
initialNotificationTitle: 'Rastreando ubicación',
initialNotificationContent: 'Servicio en ejecución',
foregroundServiceNotificationId: 888,
),
iosConfiguration: IosConfiguration(
autoStart: false,
onForeground: onStart,
onBackground: onIosBackground,
),
);
}
@pragma('vm:entry-point')
Future<bool> onIosBackground(ServiceInstance service) async {
return true;
}
@pragma('vm:entry-point')
void onStart(ServiceInstance service) async {
if (service is AndroidServiceInstance) {
service.on('setAsForeground').listen((event) {
service.setAsForegroundService();
});
service.on('setAsBackground').listen((event) {
service.setAsBackgroundService();
});
}
service.on('stopService').listen((event) {
service.stopSelf();
});
Timer.periodic(const Duration(seconds: 10), (timer) async {
if (service is AndroidServiceInstance) {
if (await service.isForegroundService()) {
service.setForegroundNotificationInfo(
title: "Rastreando ubicación",
content: "Enviando ubicación cada 10 segundos",
);
}
}
await sendLocationToApi();
service.invoke('update');
});
}
Future<void> sendLocationToApi() async {
try {
Position position = await Geolocator.getCurrentPosition(
locationSettings: const LocationSettings(
accuracy: LocationAccuracy.high,
timeLimit: Duration(seconds: 5),
),
);
final url = Uri.parse('https://api.com/test');
final response = await http.post(
url,
headers: {'Content-Type': 'application/json'},
body: jsonEncode({
'latitude': position.latitude,
'longitude': position.longitude,
'timestamp': position.timestamp.toIso8601String(),
}),
);
logger
.info('Respuesta de la API: ${response.statusCode} - ${response.body}');
if (response.statusCode != 200) {
logger.warning('Error al enviar ubicación: ${response.body}');
} else {
logger.info('Ubicación enviada con éxito: ${response.body}');
}
} catch (e) {
logger.severe('Error al obtener o enviar ubicación: $e');
}
}
Future<bool> requestLocationPermissions() async {
var locationStatus = await Permission.locationWhenInUse.request();
if (locationStatus.isGranted) {
var backgroundStatus = await Permission.locationAlways.request();
return backgroundStatus.isGranted;
}
return false;
}
void main() async {
WidgetsFlutterBinding.ensureInitialized();
_setupLogging();
final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
FlutterLocalNotificationsPlugin();
await flutterLocalNotificationsPlugin.initialize(
const InitializationSettings(
android: AndroidInitializationSettings('@mipmap/ic_launcher'),
),
);
await Geolocator.requestPermission();
if (await requestLocationPermissions()) {
await initializeService();
runApp(const MyApp());
} else {
runApp(const MyAppWithoutPermissions());
}
}
void _setupLogging() {
Logger.root.level = Level.ALL;
Logger.root.onRecord.listen((record) {
print('${record.level.name}: ${record.time}: ${record.message}');
});
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Ubicación en Segundo Plano',
theme: ThemeData(primarySwatch: Colors.blue),
home: const LocationScreen(),
);
}
}
class MyAppWithoutPermissions extends StatelessWidget {
const MyAppWithoutPermissions({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Permisos Denegados',
theme: ThemeData(primarySwatch: Colors.red),
home: const Scaffold(
body: Center(
child: Text('Se requieren permisos de ubicación para usar esta app.'),
),
),
);
}
}
class LocationScreen extends StatefulWidget {
const LocationScreen({super.key});
@override
LocationScreenState createState() => LocationScreenState();
}
class LocationScreenState extends State<LocationScreen>
with WidgetsBindingObserver {
bool _isServiceRunning = false;
final FlutterBackgroundService _service = FlutterBackgroundService();
@override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
_checkServiceStatus();
}
@override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
@override
Future<void> didChangeAppLifecycleState(AppLifecycleState state) async {
if (state == AppLifecycleState.detached) {
print('App en estado detached');
await _stopService();
print('App cerrada');
_service.invoke('kill');
}
}
Future<void> _checkServiceStatus() async {
bool isRunning = await _service.isRunning();
setState(() {
_isServiceRunning = isRunning;
});
}
Future<void> _toggleService() async {
if (_isServiceRunning) {
await _stopService();
} else {
await _startService();
}
await _checkServiceStatus();
}
Future<void> _startService() async {
await _service.startService();
}
Future<void> _stopService() async {
_service.invoke("stopService");
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Ubicación en Segundo Plano')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(_isServiceRunning
? 'El servicio está activo y enviando ubicación'
: 'El servicio está detenido'),
ElevatedButton(
onPressed: _toggleService,
child: Text(
_isServiceRunning ? 'Detener servicio' : 'Iniciar servicio'),
),
],
),
),
);
}
}