'Flutter - Dispose background service when exiting app

I built an app that tracks the location of the user even if the app is closed. But I want it to be destroyed, when the user kills the app via application exit in Android. Currently I still get the notification that the app is used in the background even if I closed it via task manager of my real device.

enter image description here

This is the message popping up after killing the app in the taskmanager, which tells that the app is still running in the background.

I am using WillStartForegroundTask from the geofence_service package.

Here is my code:

class CityDetailsScreen extends StatefulWidget {
  CityDetailsScreen();

  @override
  _CityDetailsScreenState createState() => _CityDetailsScreenState();
}

class _CityDetailsScreenState extends State<CityDetailsScreen> {
  bool permissionGranted = false;

  final geofenceService = GeofenceService.instance.setup(
     interval: 5000,
     accuracy: 100,
     loiteringDelayMs: 60000,
     statusChangeDelayMs: 10000,
     useActivityRecognition: false,
     allowMockLocations: true,
     geofenceRadiusSortType: GeofenceRadiusSortType.DESC);

 @override
 Widget build(BuildContext context) {
    return WillStartForegroundTask(
      onWillStart: () {
        // You can add a foreground task start condition.
        return geofenceService.isRunningService;
      },
      androidNotificationOptions: AndroidNotificationOptions(
        channelId: 'geofence_service_notification_channel',
        channelName: 'Geofence Service Notification',
        channelDescription:
            'This notification appears when the geofence service is running in the 
              background.',
        channelImportance: NotificationChannelImportance.HIGH,
        priority: NotificationPriority.HIGH),
        iosNotificationOptions: IOSNotificationOptions(),
        notificationTitle: 'Aschaffenburger Geheimnisse läuft im Hintergrund',
        notificationText: 'Klicke, um in die App zurückzukehren!',

           child: AnnotatedRegion<SystemUiOverlayStyle>(
                    value: SystemUiOverlayStyle.light,
                  child: Scaffold(
                            body: Container()
                         )
                     )
                  );
 }

 @override
   void dispose() {
   print("DISPOSE GeofenceService");
   GeofenceService.instance.stop();
   super.dispose();
 }
}

The service should be completely destroyed when I detach the app!

Any ideas?



Solution 1:[1]

Please review app lifecycle management via WidgetsBindingObserver. It has limits, but using the paused or inactive events should solve your problem.

This WidgetsBindingObserver issue is a good introduction into the possibilities and problems of it, especially that you cannot rely on the detached event to be fired. It would otherwise probably be your first choice instead of paused or inactive.

Here is example code to try the WidgetsBindingObserver functionality:

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() {
    return _MyHomePageState();
  }
}

class _MyHomePageState extends State<MyHomePage> with WidgetsBindingObserver {

  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addObserver(this);
  }

  @override
  void dispose() {
    WidgetsBinding.instance.removeObserver(this);
    super.dispose();
  }

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    print(state);
    if (state in [AppLifecycleState.paused, AppLifecycleState.inactive]) {
      // GeofenceService.instance.stop();
    }
    if (state == AppLifecycleState.resumed) {
      // GeofenceService.instance.setup(...);
    }
  }

  @override
  Widget build(BuildContext context) {    

    return WillPopScope(
      onWillPop: () async {
        //do something here before pop
        return true;
      },
      child: Scaffold(
        body: Container(),
      ),
    );
  }
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1