fluttergeolocatorflutter-workmanager

get location updates every 15 mins


I want to get updates on my location every 15 mins even when the phone sleeps and when the app is minimized. I am currently using workmanager and geolocator to get it but it doesn't work. It kept showing me that the location updates is stopped and disposed when I start

void main() async {
  _handleLocationPermission();
  await Workmanager().initialize(callbackDispatcher, isInDebugMode: true);
  runApp(MyApp());
}


Future<void> _getCurrentPosition() async {
  final hasPermission = await _handleLocationPermission();
  if (!hasPermission) return;
  await Geolocator.getCurrentPosition(
    desiredAccuracy: LocationAccuracy.high,
  ).then((Position position) {
    _currentPosition = position;
    print(_currentPosition);
  }).catchError((e) {
    debugPrint(e);
  });
}

@pragma(
    'vm:entry-point') // Mandatory if the App is obfuscated or using Flutter 3.1+
void callbackDispatcher() {
  Workmanager().executeTask((task, inputData) async {
    switch (task) {
      case simpleTaskKey:
        print('executed');
         _getCurrentPosition();
        print("${ScheduledTask.taskName} was executed. inputData = $inputData");
        break;
    }

    return Future.value(true);
  });
}

I am calling this ScheduledTask in another file like this, ScheduledTask.control();. When the user pressed on the button, it will start the timer using the workmanager.

  class ScheduledTask {
      static const String taskName = simpleTaskKey;
      static void control() {
        _getCurrentPosition();
        Workmanager().registerPeriodicTask(
            ScheduledTask.taskName, ScheduledTask.taskName,
            frequency: Duration(minutes: 15),
            existingWorkPolicy: ExistingWorkPolicy.append);
        // add your control here
      }
    }

When the interval is up, it shows a notification that the function has been executed but the location somehow is still not. In the debug console, it is showing this,

D/FlutterGeolocator(10382): Disposing Geolocator services
E/FlutterGeolocator(10382): Geolocator position updates stopped
D/FlutterGeolocator(10382): Stopping location service.
I/WM-WorkerWrapper(10382): Worker result SUCCESS for Work [ id=55a8af72-af00-4039-ad88-8fe07e46a58d, tags={ be.tramckrijte.workmanager.BackgroundWorker } ]
I/WM-WorkerWrapper(10382): Setting status to enqueued for b76febdc-ae5e-47b5-8294-3db31dc0e17a
W/FlutterJNI(10382): Tried to send a platform message response, but FlutterJNI was detached from native C++. Could not send. Response ID: 3

Is there something wrong with my code? I tried using StreamSubscription as well but it didnt work for me. Any guide?


Solution

  • Here is my answer.

    Future<void> onStart(ServiceInstance service) async {
      // Only available for flutter 3.0.0 and later
      DartPluginRegistrant.ensureInitialized();
      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();
      });
    
      print('Flutter Background Service : ${DateTime.now()}');
    }
      Future<void> initializeService() async {
      final service = FlutterBackgroundService();
      const AndroidNotificationChannel channel = AndroidNotificationChannel(
        'my_foreground', // id
        'MY FOREGROUND SERVICE', // 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();
      await flutterLocalNotificationsPlugin
          .resolvePlatformSpecificImplementation<
              AndroidFlutterLocalNotificationsPlugin>()
          ?.createNotificationChannel(channel);
    
    
      await service.configure(
        androidConfiguration: AndroidConfiguration(
          // this will be executed when app is in foreground or background in separated isolate
          onStart: onStart,
    
          // auto start service
          autoStart: true,
          isForegroundMode: true,
          notificationChannelId: 'my_foreground',
          initialNotificationTitle: 'Supercare Services',
          initialNotificationContent: 'Fetching current location for checkout...',
          foregroundServiceNotificationId: 888,
        ),
        iosConfiguration: IosConfiguration(
          // auto start service
          autoStart: true,
          onBackground: onIosBackground,
    
          // this will be executed when app is in foreground in separated isolate
          onForeground: onStart,
    
          // you have to enable background fetch capability on xcode project
        ),
      );
      service.startService();
    }
    
    @pragma('vm:entry-point')
    Future<bool> onIosBackground(ServiceInstance service) async {
      WidgetsFlutterBinding.ensureInitialized();
      DartPluginRegistrant.ensureInitialized();
    
      service.on('stopService').listen((event) {
        service.stopSelf();
      });
      return true;
    }
    

    Remember to set your location permission to always allow if you want to fetch location in background.

    In my case, I will need to request user to allow location permission to While Using. After that, you can request to "Always Allow" so that you can fetch location in background.

      var status = await Permission.locationWhenInUse.status;
      if (status.isGranted) { //if the status above is granted
        var status = await Permission.locationAlways.request(); //if granted, request to always allow
        if (status.isGranted) { //if always allow is granted
          await initializeService(); //start the background service
    

    } }