diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index 2652ad7..b3ad3fa 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -8,17 +8,30 @@
+
+ android:exported="false" />
+
+
+
+
+
+
+
+
+
+
{
token: authProvider.token,
geoId: shareProvider.geoId,
);
+ FlutterForegroundTask.setTaskHandler(BackgroundTaskHandler());
await bgGeo.start();
} catch (e) {
if (!mounted) return;
diff --git a/lib/services/background_geo_service.dart b/lib/services/background_geo_service.dart
index 04c4b44..947a21d 100644
--- a/lib/services/background_geo_service.dart
+++ b/lib/services/background_geo_service.dart
@@ -1,8 +1,8 @@
import 'dart:async';
import 'dart:convert';
-import 'package:flutter/foundation.dart';
-import 'package:flutter_background_geolocation/flutter_background_geolocation.dart' as bg;
+import 'package:flutter_foreground_task/flutter_foreground_task.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
+import 'package:geolocator/geolocator.dart';
import 'package:http/http.dart' as http;
import '../config/api.dart';
@@ -19,11 +19,10 @@ class BackgroundGeoService {
String? _token;
String? _geoId;
bool _isReady = false;
- bool _isStarted = false;
bool _notificationsInitialized = false;
bool get isReady => _isReady;
- bool get isStarted => _isStarted;
+ Future get isStarted async => await FlutterForegroundTask.isRunningService;
String? get token => _token;
String? get geoId => _geoId;
@@ -33,11 +32,7 @@ class BackgroundGeoService {
const androidSettings = AndroidInitializationSettings(
'@mipmap/ic_launcher',
);
- const iosSettings = DarwinInitializationSettings(
- requestAlertPermission: true,
- requestBadgePermission: true,
- requestSoundPermission: true,
- );
+ const iosSettings = DarwinInitializationSettings();
const initSettings = InitializationSettings(
android: androidSettings,
iOS: iosSettings,
@@ -61,69 +56,59 @@ class BackgroundGeoService {
await initNotifications();
- bg.BackgroundGeolocation.onLocation(_onLocation, _onLocationError);
- bg.BackgroundGeolocation.onMotionChange(_onMotionChange);
- bg.BackgroundGeolocation.onProviderChange(_onProviderChange);
- bg.BackgroundGeolocation.onHttp(_onHttp);
+ FlutterForegroundTask.initCommunicationPort();
- await bg.BackgroundGeolocation.ready(bg.Config(
- desiredAccuracy: bg.Config.DESIRED_ACCURACY_HIGH,
- distanceFilter: 10.0,
- stopOnTerminate: false,
- startOnBoot: true,
- debug: false,
- logLevel: bg.Config.LOG_LEVEL_OFF,
- autoSync: false,
- ));
+ FlutterForegroundTask.addTaskDataCallback(_onTaskData);
_isReady = true;
}
Future start() async {
if (!_isReady) return;
- if (_isStarted) return;
if (_token == null || _geoId == null || _geoId!.isEmpty) return;
- await bg.BackgroundGeolocation.start();
- _isStarted = true;
+ final androidOptions = AndroidNotificationOptions(
+ channelId: 'background_geo_channel',
+ channelName: 'Background Geolocation',
+ channelDescription: 'Отслеживание позиции в фоновом режиме',
+ channelImportance: NotificationChannelImportance.HIGH,
+ priority: NotificationPriority.HIGH,
+ );
+
+ final iosOptions = IOSNotificationOptions(
+ showNotification: true,
+ playSound: true,
+ );
+
+ final taskOptions = ForegroundTaskOptions(
+ eventAction: ForegroundTaskEventAction.repeat(15000),
+ autoRunOnBoot: true,
+ allowWakeLock: true,
+ );
+
+ FlutterForegroundTask.init(
+ androidNotificationOptions: androidOptions,
+ iosNotificationOptions: iosOptions,
+ foregroundTaskOptions: taskOptions,
+ );
+
+ await FlutterForegroundTask.startService(
+ notificationTitle: 'Family Safety',
+ notificationText: 'Отслеживание позиции активно',
+ );
}
Future stop() async {
- if (!_isStarted) return;
- await bg.BackgroundGeolocation.stop();
- _isStarted = false;
+ await FlutterForegroundTask.stopService();
}
void dispose() {
- bg.BackgroundGeolocation.removeListeners();
_isReady = false;
- _isStarted = false;
_token = null;
_geoId = null;
}
- void _onLocation(bg.Location location) {
- if (_token == null || _geoId == null || _geoId!.isEmpty) return;
- if (location.sample == true) return;
-
- _sendPosition(location.coords.latitude, location.coords.longitude);
- }
-
- void _onLocationError(bg.LocationError error) {
- _showErrorNotification('Ошибка геолокации: $error');
- }
-
- void _onMotionChange(bg.Location location) {
- kDebugMode? print('[BackgroundGeo] Motion changed: isMoving=${location.isMoving}'):{};
- }
-
- void _onProviderChange(bg.ProviderChangeEvent event) {
- kDebugMode?print('[BackgroundGeo] Provider changed: $event'):{};
- }
-
- void _onHttp(bg.HttpEvent event) {
- kDebugMode? print('[BackgroundGeo] HTTP: status=${event.status}, success=${event.success}'):{};
- }
+ static void _onTaskData(Object data) {}
Future _sendPosition(double latitude, double longitude) async {
if (_token == null || _geoId == null || _geoId!.isEmpty) return;
@@ -162,10 +147,7 @@ class BackgroundGeoService {
priority: Priority.high,
ticker: 'geo_error',
);
- const iosDetails = DarwinNotificationDetails(
- presentAlert: true,
- sound: 'default',
- );
+ const iosDetails = DarwinNotificationDetails();
const details = NotificationDetails(
android: androidDetails,
iOS: iosDetails,
@@ -184,3 +166,45 @@ class BackgroundGeoService {
print('[Notification] ${response.payload}');
}
}
+
+class BackgroundTaskHandler extends TaskHandler {
+ int _locationCount = 0;
+
+ @override
+ Future onStart(DateTime timestamp, TaskStarter starter) async {}
+
+ @override
+ void onRepeatEvent(DateTime timestamp) {
+ _locationCount++;
+
+ if (_locationCount % 2 != 0) return;
+
+ _getLocationAndSend();
+ }
+
+ @override
+ void onReceiveData(Object data) {}
+
+ @override
+ void onNotificationButtonPressed(String id) {}
+
+ @override
+ void onNotificationPressed() {}
+
+ @override
+ void onNotificationDismissed() {}
+
+ @override
+ Future onDestroy(DateTime timestamp) async {}
+
+ Future _getLocationAndSend() async {
+ try {
+ final position = await Geolocator.getCurrentPosition();
+
+ final bgGeo = BackgroundGeoService();
+ await bgGeo._sendPosition(position.latitude, position.longitude);
+ } catch (e) {
+ print('[BackgroundGeo] Error getting location: $e');
+ }
+ }
+}
diff --git a/pubspec.lock b/pubspec.lock
index 2703b3e..a0e37bf 100644
--- a/pubspec.lock
+++ b/pubspec.lock
@@ -17,14 +17,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.13.1"
- background_fetch:
- dependency: transitive
- description:
- name: background_fetch
- sha256: a185b471f6ff93c0074e2da98fbdf1e0c5af5a83adb97dfe924a9ef06c9e0175
- url: "https://pub.dev"
- source: hosted
- version: "1.7.0"
boolean_selector:
dependency: transitive
description:
@@ -118,14 +110,14 @@ packages:
description: flutter
source: sdk
version: "0.0.0"
- flutter_background_geolocation:
+ flutter_foreground_task:
dependency: "direct main"
description:
- name: flutter_background_geolocation
- sha256: "2c5f23bf35837b31c4e1badadf7fb5da418a1862133b5a671b3e0bfa60c3bf2f"
+ name: flutter_foreground_task
+ sha256: "206017ee1bf864f34b8d7bce664a172717caa21af8da23f55866470dfe316644"
url: "https://pub.dev"
source: hosted
- version: "4.18.3"
+ version: "8.17.0"
flutter_lints:
dependency: "direct dev"
description:
@@ -668,4 +660,4 @@ packages:
version: "6.6.1"
sdks:
dart: ">=3.10.1 <4.0.0"
- flutter: ">=3.38.0"
+ flutter: ">=3.35.0"
diff --git a/pubspec.yaml b/pubspec.yaml
index 57ae472..9596379 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -42,7 +42,7 @@ dependencies:
latlong2: ^0.9.1
geolocator: ^14.0.2
shared_preferences: ^2.2.2
- flutter_background_geolocation: ^4.13.0
+ flutter_foreground_task: ^8.0.0
flutter_local_notifications: ^18.0.1
dev_dependencies:
diff --git a/test/widget_test.dart b/test/widget_test.dart
index c2a4a2a..cc8b9da 100644
--- a/test/widget_test.dart
+++ b/test/widget_test.dart
@@ -16,7 +16,6 @@ void main() {
testWidgets('App loads login screen', (WidgetTester tester) async {
final bgGeo = BackgroundGeoService();
await bgGeo.init();
- await bgGeo.initNotifications();
await tester.pumpWidget(MyApp(
settingsService: SettingsService(),
bgGeo: bgGeo,