From 193a193e8a8f284efd749a22a998200de48177d2 Mon Sep 17 00:00:00 2001 From: Janez T Date: Tue, 10 Mar 2026 19:56:24 +0100 Subject: [PATCH] Ensure constant iOS location updates --- ios/Runner/Info.plist | 1 + lib/services/background_location_service.dart | 32 ++++++++++++- lib/services/location_tracking_service.dart | 45 +++++++++++++++++-- 3 files changed, 72 insertions(+), 6 deletions(-) diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index 23eda06..eac98b6 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -102,6 +102,7 @@ UIBackgroundModes location + bluetooth-central bluetooth-peripheral UILaunchStoryboardName diff --git a/lib/services/background_location_service.dart b/lib/services/background_location_service.dart index c93dcd5..04ced60 100644 --- a/lib/services/background_location_service.dart +++ b/lib/services/background_location_service.dart @@ -1,4 +1,5 @@ import 'dart:async'; +import 'dart:io'; import 'package:flutter/widgets.dart'; import 'package:geolocator/geolocator.dart'; import 'package:shared_preferences/shared_preferences.dart'; @@ -58,6 +59,16 @@ class BackgroundLocationService { return false; } + if (Platform.isIOS && permission != LocationPermission.always) { + permission = await Geolocator.requestPermission(); + if (permission != LocationPermission.always) { + debugPrint( + '⚠️ [BackgroundLocation] iOS background tracking requires Always permission', + ); + return false; + } + } + // Save settings final prefs = await SharedPreferences.getInstance(); await prefs.setBool(_prefKeyEnabled, true); @@ -68,8 +79,7 @@ class BackgroundLocationService { try { _positionSubscription = Geolocator.getPositionStream( - locationSettings: LocationSettings( - accuracy: LocationAccuracy.best, + locationSettings: _buildLocationSettings( distanceFilter: distanceThreshold.toInt(), ), ).listen((Position position) async { @@ -171,4 +181,22 @@ class BackgroundLocationService { await startTracking(distanceThreshold: distance); } } + + LocationSettings _buildLocationSettings({int distanceFilter = 10}) { + if (Platform.isIOS) { + return AppleSettings( + accuracy: LocationAccuracy.best, + activityType: ActivityType.fitness, + allowBackgroundLocationUpdates: true, + distanceFilter: distanceFilter, + pauseLocationUpdatesAutomatically: false, + showBackgroundLocationIndicator: true, + ); + } + + return LocationSettings( + accuracy: LocationAccuracy.best, + distanceFilter: distanceFilter, + ); + } } diff --git a/lib/services/location_tracking_service.dart b/lib/services/location_tracking_service.dart index c70c339..1b4a940 100644 --- a/lib/services/location_tracking_service.dart +++ b/lib/services/location_tracking_service.dart @@ -1,4 +1,5 @@ import 'dart:async'; +import 'dart:io'; import 'package:flutter/foundation.dart'; import 'package:geolocator/geolocator.dart'; import 'package:shared_preferences/shared_preferences.dart'; @@ -148,6 +149,10 @@ class LocationTrackingService { /// Check if location permissions are granted Future checkPermissions() async { final permission = await Geolocator.checkPermission(); + if (Platform.isIOS) { + return permission == LocationPermission.always; + } + return permission == LocationPermission.always || permission == LocationPermission.whileInUse; } @@ -181,6 +186,16 @@ class LocationTrackingService { return false; } + if (Platform.isIOS && permission != LocationPermission.always) { + permission = await Geolocator.requestPermission(); + if (permission != LocationPermission.always) { + onError?.call( + 'Background tracking on iOS requires "Always" location access. Enable it in Settings.', + ); + return false; + } + } + debugPrint('✅ [LocationTracking] Location permissions granted'); return true; } @@ -209,9 +224,9 @@ class LocationTrackingService { } final position = await Geolocator.getCurrentPosition( - locationSettings: LocationSettings( - accuracy: LocationAccuracy.best, + locationSettings: _buildLocationSettings( timeLimit: timeLimit, + distanceFilter: 0, ), ); @@ -255,13 +270,35 @@ class LocationTrackingService { /// [distanceFilter] - Minimum distance in meters between position updates Stream getPositionStream({double distanceFilter = 10.0}) { return Geolocator.getPositionStream( - locationSettings: LocationSettings( - accuracy: LocationAccuracy.best, + locationSettings: _buildLocationSettings( distanceFilter: distanceFilter.toInt(), ), ); } + LocationSettings _buildLocationSettings({ + int distanceFilter = 10, + Duration? timeLimit, + }) { + if (Platform.isIOS) { + return AppleSettings( + accuracy: LocationAccuracy.best, + activityType: ActivityType.fitness, + allowBackgroundLocationUpdates: true, + distanceFilter: distanceFilter, + pauseLocationUpdatesAutomatically: false, + showBackgroundLocationIndicator: true, + timeLimit: timeLimit, + ); + } + + return LocationSettings( + accuracy: LocationAccuracy.best, + distanceFilter: distanceFilter, + timeLimit: timeLimit, + ); + } + // ============================================================================ // Tracking Control // ============================================================================