Anonymous
Местоположение фона iOS работает в отладке, но не в выпуске (Flutter)
Сообщение
Anonymous » 12 авг 2025, 10:10
Я использую Flutter с Flutter_background_service и Geolocator для получения обновлений местоположения в фоновом режиме.
В режиме отладки
, фоновое местоположение работает нормально, даже когда приложение минимизировано или заблокирован экран. Любые обновления местоположения фона.
Код: Выделить всё
UIBackgroundModes
fetch
location
remote-notification
processing
NSLocationAlwaysAndWhenInUseUsageDescription
Your location is needed even when the app is in the background to track trips.
NSLocationAlwaysUsageDescription
Your location is needed even when the app is in the background to track trips.
NSLocationTemporaryUsageDescriptionDictionary
LocationTracking
This app needs precise location for school bus tracking and safety monitoring purposes.
NSLocationWhenInUseUsageDescription
Your location is needed to track trips while the app is open.
BGTaskSchedulerPermittedIdentifiers
dev.flutter.background.refresh
backgorundservice
Код: Выделить всё
class BackgroundServiceController extends ChangeNotifier {
static final BackgroundServiceController _instance =
BackgroundServiceController._internal();
factory BackgroundServiceController() => _instance;
BackgroundServiceController._internal();
final FlutterBackgroundService _service = FlutterBackgroundService();
Future initializeService({
required int? disInterval,
required int? timeInterval,
}) async {
SessionController().setDistanceAndTimeInterval(
disInterval: disInterval.toString(),
timeInterval: timeInterval.toString(),
);
final isRunning = await _service.isRunning();
if (isRunning) {
await Future.delayed(const Duration(seconds: 1));
_service.invoke('setData');
return;
}
const AndroidNotificationChannel channel = AndroidNotificationChannel(
'my_foreground',
'MY FOREGROUND SERVICE',
description:
'This channel is used for important notifications.',
importance: Importance.low,
);
final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
FlutterLocalNotificationsPlugin();
if (Platform.isIOS || Platform.isAndroid) {
await flutterLocalNotificationsPlugin.initialize(
const InitializationSettings(
iOS: DarwinInitializationSettings(),
android: AndroidInitializationSettings('logo'),
),
);
}
await flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin
>()
?.createNotificationChannel(channel);
await _service.configure(
androidConfiguration: AndroidConfiguration(
onStart: onStart,
autoStart: true,
isForegroundMode: true,
autoStartOnBoot: true,
notificationChannelId: 'my_foreground',
initialNotificationTitle: 'Location Service',
initialNotificationContent: 'Initializing...',
foregroundServiceNotificationId: 888,
foregroundServiceTypes: [AndroidForegroundType.location],
),
iosConfiguration: IosConfiguration(
autoStart: true,
onForeground: onStart,
onBackground: onIosBackground,
),
);
try {
await _service.startService();
} catch (e) {
}
while (!(await _service.isRunning())) {
await Future.delayed(const Duration(milliseconds: 200));
}
await Future.delayed(const Duration(seconds: 3));
_service.invoke('setData');
}
Future stopService() async {
final isRunning = await _service.isRunning();
if (isRunning) {
_service.invoke("stopService");
} else {
}
}
Future isServiceRunning() async {
return await _service.isRunning();
}
}
@pragma('vm:entry-point')
void onStart(ServiceInstance service) async {
// DartPluginRegistrant.ensureInitialized();
WidgetsFlutterBinding.ensureInitialized();
await AppConstants.init();
await SessionController().init();
final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
FlutterLocalNotificationsPlugin();
final disInterval = SessionController().disInterval ?? 20;
final timeInterval = SessionController().timeInterval ?? 10;
StreamSubscription
? positionStream;
final homeViewModel = HomeViewModel();
void startLocationTracking() async {
if (positionStream != null) {
return;
}
DateTime? lastSentTime;
positionStream =
Geolocator.getPositionStream(
locationSettings: const LocationSettings(
distanceFilter: 0,
accuracy: LocationAccuracy.bestForNavigation,
),
).listen((position) async {
final now = DateTime.now();
if (lastSentTime == null ||
now.difference(lastSentTime!).inSeconds >= (timeInterval)) {
lastSentTime = now;
try {
await homeViewModel.pushLiveLocation(position: position);
} catch (e) {
}
} else {
}
});
}
service.on('stopService').listen((event) async {
await positionStream?.cancel();
positionStream = null;
await service.stopSelf();
});
service.on('setData').listen((data) async {
final disInterval = SessionController().disInterval ?? 20;
final timeInterval = SessionController().timeInterval ?? 10;
await Future.delayed(const Duration(seconds: 5));
startLocationTracking();
});
if (service is AndroidServiceInstance &&
await service.isForegroundService()) {
flutterLocalNotificationsPlugin.show(
888,
'Tracking location in background',
'Background location is on to keep the app up-tp-date with your location. This is required for main features to work properly when the app is not running.',
const NotificationDetails(
android: AndroidNotificationDetails(
'my_foreground',
'MY FOREGROUND SERVICE',
icon: 'ic_stat_notification',
ongoing: true,
styleInformation: BigTextStyleInformation(
'Background location is on to keep the app up-to-date with your location. '
'This is required for main features to work properly when the app is not running.',
contentTitle: 'Tracking location in background',
htmlFormatContent: true,
),
),
),
);
// service.setForegroundNotificationInfo(
// title: "Location Tracking",
// content: "Tracking your location in background",
// );
}
}
@pragma('vm:entry-point')
Future onIosBackground(ServiceInstance service) async {
// DartPluginRegistrant.ensureInitialized();
WidgetsFlutterBinding.ensureInitialized();
await AppConstants.init();
await SessionController().init();
final homeViewModel = HomeViewModel();
try {
final disInterval = SessionController().disInterval ?? 20;
final sub =
Geolocator.getPositionStream(
locationSettings: const LocationSettings(
distanceFilter: 0,
accuracy: LocationAccuracy.bestForNavigation,
),
).listen((position) async {
try {
await homeViewModel.pushLiveLocation(position: position);
} catch (e) {
}
});
await Future.delayed(const Duration(seconds: 30));
await sub.cancel();
} catch (e) {
}
return true;
}
Я также проверил, что приложение всегда разрешает разрешение на местоположение в настройках iOS
Подробнее здесь:
https://stackoverflow.com/questions/797 ... se-flutter
1754982601
Anonymous
Я использую Flutter с Flutter_background_service и Geolocator для получения обновлений местоположения в фоновом режиме. В режиме отладки [b] [/b], фоновое местоположение работает нормально, даже когда приложение минимизировано или заблокирован экран. Любые обновления местоположения фона.[code]UIBackgroundModes fetch location remote-notification processing NSLocationAlwaysAndWhenInUseUsageDescription Your location is needed even when the app is in the background to track trips. NSLocationAlwaysUsageDescription Your location is needed even when the app is in the background to track trips. NSLocationTemporaryUsageDescriptionDictionary LocationTracking This app needs precise location for school bus tracking and safety monitoring purposes. NSLocationWhenInUseUsageDescription Your location is needed to track trips while the app is open. BGTaskSchedulerPermittedIdentifiers dev.flutter.background.refresh [/code] [b] backgorundservice [/b] [code]class BackgroundServiceController extends ChangeNotifier { static final BackgroundServiceController _instance = BackgroundServiceController._internal(); factory BackgroundServiceController() => _instance; BackgroundServiceController._internal(); final FlutterBackgroundService _service = FlutterBackgroundService(); Future initializeService({ required int? disInterval, required int? timeInterval, }) async { SessionController().setDistanceAndTimeInterval( disInterval: disInterval.toString(), timeInterval: timeInterval.toString(), ); final isRunning = await _service.isRunning(); if (isRunning) { await Future.delayed(const Duration(seconds: 1)); _service.invoke('setData'); return; } const AndroidNotificationChannel channel = AndroidNotificationChannel( 'my_foreground', 'MY FOREGROUND SERVICE', description: 'This channel is used for important notifications.', importance: Importance.low, ); final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin(); if (Platform.isIOS || Platform.isAndroid) { await flutterLocalNotificationsPlugin.initialize( const InitializationSettings( iOS: DarwinInitializationSettings(), android: AndroidInitializationSettings('logo'), ), ); } await flutterLocalNotificationsPlugin .resolvePlatformSpecificImplementation< AndroidFlutterLocalNotificationsPlugin >() ?.createNotificationChannel(channel); await _service.configure( androidConfiguration: AndroidConfiguration( onStart: onStart, autoStart: true, isForegroundMode: true, autoStartOnBoot: true, notificationChannelId: 'my_foreground', initialNotificationTitle: 'Location Service', initialNotificationContent: 'Initializing...', foregroundServiceNotificationId: 888, foregroundServiceTypes: [AndroidForegroundType.location], ), iosConfiguration: IosConfiguration( autoStart: true, onForeground: onStart, onBackground: onIosBackground, ), ); try { await _service.startService(); } catch (e) { } while (!(await _service.isRunning())) { await Future.delayed(const Duration(milliseconds: 200)); } await Future.delayed(const Duration(seconds: 3)); _service.invoke('setData'); } Future stopService() async { final isRunning = await _service.isRunning(); if (isRunning) { _service.invoke("stopService"); } else { } } Future isServiceRunning() async { return await _service.isRunning(); } } @pragma('vm:entry-point') void onStart(ServiceInstance service) async { // DartPluginRegistrant.ensureInitialized(); WidgetsFlutterBinding.ensureInitialized(); await AppConstants.init(); await SessionController().init(); final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin(); final disInterval = SessionController().disInterval ?? 20; final timeInterval = SessionController().timeInterval ?? 10; StreamSubscription ? positionStream; final homeViewModel = HomeViewModel(); void startLocationTracking() async { if (positionStream != null) { return; } DateTime? lastSentTime; positionStream = Geolocator.getPositionStream( locationSettings: const LocationSettings( distanceFilter: 0, accuracy: LocationAccuracy.bestForNavigation, ), ).listen((position) async { final now = DateTime.now(); if (lastSentTime == null || now.difference(lastSentTime!).inSeconds >= (timeInterval)) { lastSentTime = now; try { await homeViewModel.pushLiveLocation(position: position); } catch (e) { } } else { } }); } service.on('stopService').listen((event) async { await positionStream?.cancel(); positionStream = null; await service.stopSelf(); }); service.on('setData').listen((data) async { final disInterval = SessionController().disInterval ?? 20; final timeInterval = SessionController().timeInterval ?? 10; await Future.delayed(const Duration(seconds: 5)); startLocationTracking(); }); if (service is AndroidServiceInstance && await service.isForegroundService()) { flutterLocalNotificationsPlugin.show( 888, 'Tracking location in background', 'Background location is on to keep the app up-tp-date with your location. This is required for main features to work properly when the app is not running.', const NotificationDetails( android: AndroidNotificationDetails( 'my_foreground', 'MY FOREGROUND SERVICE', icon: 'ic_stat_notification', ongoing: true, styleInformation: BigTextStyleInformation( 'Background location is on to keep the app up-to-date with your location. ' 'This is required for main features to work properly when the app is not running.', contentTitle: 'Tracking location in background', htmlFormatContent: true, ), ), ), ); // service.setForegroundNotificationInfo( // title: "Location Tracking", // content: "Tracking your location in background", // ); } } @pragma('vm:entry-point') Future onIosBackground(ServiceInstance service) async { // DartPluginRegistrant.ensureInitialized(); WidgetsFlutterBinding.ensureInitialized(); await AppConstants.init(); await SessionController().init(); final homeViewModel = HomeViewModel(); try { final disInterval = SessionController().disInterval ?? 20; final sub = Geolocator.getPositionStream( locationSettings: const LocationSettings( distanceFilter: 0, accuracy: LocationAccuracy.bestForNavigation, ), ).listen((position) async { try { await homeViewModel.pushLiveLocation(position: position); } catch (e) { } }); await Future.delayed(const Duration(seconds: 30)); await sub.cancel(); } catch (e) { } return true; } [/code] Я также проверил, что приложение всегда разрешает разрешение на местоположение в настройках iOS Подробнее здесь: [url]https://stackoverflow.com/questions/79732808/ios-background-location-works-in-debug-but-not-in-release-flutter[/url]