flutter-geolocator
flutter-geolocator copied to clipboard
[Question]:
Please check the following before submitting a new issue.
- [X] I have searched the existing issues.
- [X] I have carefully read the documentation.
Please select for which platform(s) you need help
- [X] Android
- [ ] iOS
- [ ] Linux
- [ ] macOS
- [ ] Web
- [ ] Windows
Your question
This code works on a Pixel 6, but not on a Samsung phone. I've tried a couple of Samsung phones running Android 13 and 14. They work the same. While running a Foreground Service, the code works when the app is in the foreground, when the app in in the background the geolocator engine detaches. When the app returns to the to the foreground the geolocator updates continue. What am I doing wrong?
D/FlutterGeolocator(16946): Detaching Geolocator from activity D/FlutterGeolocator(16946): Flutter engine disconnected. Connected engine count 1 D/FlutterGeolocator(16946): Disposing Geolocator services E/FlutterGeolocator(16946): Geolocator position updates stopped
final position = await Geolocator.getCurrentPosition(
desiredAccuracy: LocationAccuracy.best,
forceAndroidLocationManager: true,
timeLimit: const Duration(minutes: 5),
);
on line 163 never returns, or since I added the timeout it gets a timeout.
import 'dart:async';
import 'dart:io';
import 'dart:ui';
import 'package:device_info_plus/device_info_plus.dart';
import 'package:flutter/material.dart';
import 'package:flutter_background_service/flutter_background_service.dart';
import 'package:flutter_background_service_android/flutter_background_service_android.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:geocoding/geocoding.dart';
import 'package:geolocator/geolocator.dart';
import 'package:shared_preferences/shared_preferences.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await requestLocationPermissions();
await initializeService();
runApp(const MyApp());
}
Future<void> initializeService() async {
final service = FlutterBackgroundService();
/// OPTIONAL, using custom notification channel id
const AndroidNotificationChannel channel = AndroidNotificationChannel(
'rendezvous_service', // id
'command channel', // title
description:
'This channel is used for important notifications.', // description
importance: Importance.low, // importance must be at low or higher level
);
final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
FlutterLocalNotificationsPlugin();
if (Platform.isIOS || Platform.isAndroid) {
await flutterLocalNotificationsPlugin.initialize(
const InitializationSettings(
iOS: DarwinInitializationSettings(),
android: AndroidInitializationSettings('ic_bg_service_small'),
),
);
}
await flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin>()
?.createNotificationChannel(channel);
await service.configure(
// THis service will be in the foreground
androidConfiguration: AndroidConfiguration(
// this will be executed when app is in foreground or background in separated isolate
onStart: onStart,
autoStart: true,
isForegroundMode: true,
notificationChannelId: 'rendezvous_service',
initialNotificationTitle: 'AWESOME SERVICE',
initialNotificationContent: 'Initializing',
foregroundServiceNotificationId: 888,
),
iosConfiguration: IosConfiguration(
// auto start service
autoStart: true,
// this will be executed when app is in foreground in separated isolate
onForeground: onStart,
// you have to enable background fetch capability on xcode project
onBackground: onIosBackground,
),
);
}
// to ensure this is executed
// run app from xcode, then from xcode menu, select Simulate Background Fetch
@pragma('vm:entry-point')
Future<bool> onIosBackground(ServiceInstance service) async {
WidgetsFlutterBinding.ensureInitialized();
DartPluginRegistrant.ensureInitialized();
SharedPreferences preferences = await SharedPreferences.getInstance();
await preferences.reload();
final log = preferences.getStringList('log') ?? <String>[];
log.add(DateTime.now().toIso8601String());
await preferences.setStringList('log', log);
return true;
}
@pragma('vm:entry-point')
void onStart(ServiceInstance service) async {
// Only available for flutter 3.0.0 and later
DartPluginRegistrant.ensureInitialized();
SharedPreferences preferences = await SharedPreferences.getInstance();
await preferences.setString("hello", "world");
/// OPTIONAL when use custom notification
final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
FlutterLocalNotificationsPlugin();
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: 30), (timer) async {
try {
if (service is AndroidServiceInstance) {
/// Per Android policy, a foreground service is required to provide
/// persistent notifications for transparency to the user.
/// Is monitored by system resource management. If not done, the service
/// will be terminated
if (await service.isForegroundService()) {
flutterLocalNotificationsPlugin.show(
888,
'Firebase Update',
'Location Updated At ${DateTime.now()}',
const NotificationDetails(
android: AndroidNotificationDetails(
'rendezvous_service',
'COMMANDs',
icon: 'ic_bg_service_small',
ongoing: true,
),
),
);
// if you don't using custom notification, uncomment this
service.setForegroundNotificationInfo(
title: "My App Service",
content: "Updated at ${DateTime.now()}",
);
}
try {
// Get current location
print('******************* updateLocation');
bool serviceEnabled = await Geolocator.isLocationServiceEnabled();
if (!serviceEnabled) {
Fluttertoast.showToast(msg: "Location services are not enabled");
return Future.error('Location services are not enabled');
}
LocationPermission permission = await Geolocator.checkPermission();
if (permission == LocationPermission.denied) {
//permission = await _geolocatorPlatform.requestPermission();
permission = await Geolocator.requestPermission();
if (permission == LocationPermission.denied) {
Fluttertoast.showToast(msg: "Location permission denied");
return Future.error("Location permission denied by user");
}
}
if (permission == LocationPermission.deniedForever) {
Fluttertoast.showToast(msg: "Location permission denied forever");
return Future.error("Location permission permanently denied");
}
print('past permissions calling getposition');
final position = await Geolocator.getCurrentPosition(
desiredAccuracy: LocationAccuracy.best,
forceAndroidLocationManager: true,
timeLimit: const Duration(minutes: 5),
);
print('past getCurrentPosition: $position');
String address = '';
// geocoding only runs on android. Get the address.
List<Placemark> placemarks = await placemarkFromCoordinates(
position.latitude, position.longitude);
if (placemarks.isNotEmpty) {
Placemark placemark = placemarks[0];
address =
"${placemark.street}, ${placemark.locality}, ${placemark.administrativeArea}, ${placemark.country}";
}
print('updateLocation position:$position address: $address');
} on Exception catch (e) {
print('update_location exception:\n $e');
}
/// you can see this log in logcat
if (await service.isForegroundService()) {
print('FLUTTER FOREGROUND SERVICE: ${DateTime.now()}');
} else {
print('FLUTTER BACKGROUND SERVICE: ${DateTime.now()}');
}
// test using external plugin
final deviceInfo = DeviceInfoPlugin();
String? device;
if (Platform.isAndroid) {
final androidInfo = await deviceInfo.androidInfo;
device = androidInfo.model;
}
if (Platform.isIOS) {
final iosInfo = await deviceInfo.iosInfo;
device = iosInfo.model;
}
service.invoke(
'update',
{
"current_date": DateTime.now().toIso8601String(),
"device": device,
},
);
}
} on Exception catch (e) {
print('Service exception:\n $e');
}
});
}
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
String text = "Stop Service";
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Service App'),
),
body: Column(
children: [
StreamBuilder<Map<String, dynamic>?>(
stream: FlutterBackgroundService().on('update'),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return const Center(
child: CircularProgressIndicator(),
);
}
final data = snapshot.data!;
String? device = data["device"];
DateTime? date = DateTime.tryParse(data["current_date"]);
return Column(
children: [
Text(device ?? 'Unknown'),
Text(date.toString()),
],
);
},
),
ElevatedButton(
child: const Text("Foreground Mode"),
onPressed: () {
FlutterBackgroundService().invoke("setAsForeground");
},
),
ElevatedButton(
child: const Text("Background Mode"),
onPressed: () {
FlutterBackgroundService().invoke("setAsBackground");
},
),
ElevatedButton(
child: Text(text),
onPressed: () async {
final service = FlutterBackgroundService();
var isRunning = await service.isRunning();
if (isRunning) {
service.invoke("stopService");
} else {
service.startService();
}
if (!isRunning) {
text = 'Stop Service';
} else {
text = 'Start Service';
}
setState(() {});
},
),
// const Expanded(
// child: LogView(),
// ),
],
),
floatingActionButton: FloatingActionButton(
onPressed: () {},
child: const Icon(Icons.play_arrow),
),
),
);
}
}
Future<void> requestLocationPermissions() async {
bool serviceEnabled = await Geolocator.isLocationServiceEnabled();
if (!serviceEnabled) {
print('location service is not enabled');
Fluttertoast.showToast(msg: "Location services are not enabled");
return Future.error('Location services are not enabled');
}
LocationPermission permission = await Geolocator.checkPermission();
if (permission == LocationPermission.denied) {
//permission = await _geolocatorPlatform.requestPermission();
permission = await Geolocator.requestPermission();
if (permission == LocationPermission.denied) {
print('request permissions');
Fluttertoast.showToast(msg: "Location permission denied");
return Future.error("Location permission denied by user");
}
}
if (permission == LocationPermission.deniedForever) {
print('location denied forever');
Fluttertoast.showToast(msg: "Location permission denied forever");
return Future.error("Location permission permanently denied");
}
}
Version
^11.0.0
From docs:
Starting from Android 10 you need to add the ACCESS_BACKGROUND_LOCATION permission (next to the ACCESS_COARSE_LOCATION or the ACCESS_FINE_LOCATION permission) if you want to continue receiving updates even when your App is running in the background (note that the geolocator plugin doesn't support receiving and processing location updates while running in the background):
I am Facing same issue Geolocator.getPositionStream().listen((Position position) { currentPosition = position; myPostion = position; LatLng mPostion = LatLng(position.latitude, position.longitude); when app is in background in samsung update version 1 april 2024 when app is in background then location is not fetch only work in foreground only new latest version it is not working
Dear @grecky-goo,
Has your issue been resolved with the help of @dmiedev? I'll close this issue for now. Feel free to reopen the issue or open a new issue with additional information.
Kind regards,
Dear @nitinkhanduri,
Could you file a separate issue with some additional background information? It might be unrelated.
Kind regards