1

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?

wuuyungwuu
  • 83
  • 13

2 Answers2

0

I found an easy package that may help you package name : flutter_background_geolocation you can find it on pub.dev .

here is an example how to use it :

import 'package:flutter_background_geolocation/flutter_background_geolocation.dart' as bg;

class _MyHomePageState extends State<MyHomePage> {

  @override
  void initState() {
    super.initState();

    ////
    // 1.  Listen to events (See docs for all 12 available events).
    //

    // Fired whenever a location is recorded
    bg.BackgroundGeolocation.onLocation((bg.Location location) {
      print('[location] - $location');
    });

    // Fired whenever the plugin changes motion-state (stationary->moving and vice-versa)
    bg.BackgroundGeolocation.onMotionChange((bg.Location location) {
      print('[motionchange] - $location');
    });

    // Fired whenever the state of location-services changes.  Always fired at boot
    bg.BackgroundGeolocation.onProviderChange((bg.ProviderChangeEvent event) {
      print('[providerchange] - $event');
    });

    ////
    // 2.  Configure the plugin
    //
    bg.BackgroundGeolocation.ready(bg.Config(
        desiredAccuracy: bg.Config.DESIRED_ACCURACY_HIGH,
        distanceFilter: 10.0,
        stopOnTerminate: false,
        startOnBoot: true,
        debug: true,
        logLevel: bg.Config.LOG_LEVEL_VERBOSE
    )).then((bg.State state) {
      if (!state.enabled) {
        ////
        // 3.  Start the plugin.
        //
        bg.BackgroundGeolocation.start();
      }
    });
  }
}
0

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

} }

wuuyungwuu
  • 83
  • 13