Search code examples
restflutterbackground-process

Ensure processing of a REST call in flutter app in background


I need to ensure that a certain HTTP request was send successfully. Therefore, I'm wondering if a simple way exists to move such a request into a background service task.

The background of my question is the following: We're developing a survey application using flutter. Unfortunately, the app is intended to be used in an environment where no mobile internet connection can be guaranteed. Therefore, I’m not able to simply post the result of the survey one time but I have to retry it if it fails due to network problems. My current code looks like the following. The problem with my current solution is that it only works while the app is active all the time. If the user minimizes or closes the app, the data I want to upload is lost. Therefore, I’m looking for a solution to wrap the upload process in a background service task so that it will be processed even when the user closes the app. I found several posts and plugins (namely https://medium.com/flutter-io/executing-dart-in-the-background-with-flutter-plugins-and-geofencing-2b3e40a1a124 and https://pub.dartlang.org/packages/background_fetch) but they don’t help in my particular use case. The first describes a way how the app could be notified when a certain event (namely the geofence occurred) and the second only works every 15 minutes and focuses a different scenario as well. Does somebody knows a simple way how I can ensure that a request was processed even when there is a bad internet connection (or even none at the moment) while allowing the users to minimize or even close the app?

Future _processUploadQueue() async {
  int retryCounter = 0;
  Future.doWhile(() {
    if(retryCounter == 10){
      print('Abborted after 10 tries');
      return false;
    }
    if (_request.uploaded) {
      print('Upload ready');
      return false;
    }
    if(! _request.uploaded) {
      _networkService.sendRequest(request: _request.entry)
          .then((id){
            print(id);
            setState(() {
              _request.uploaded = true;
            });
      }).catchError((e) {
        retryCounter++;
        print(e);
      });
    }
    // e ^ retryCounter, min 0 Sec, max 10 minutes
    int waitTime = min(max(0, exp(retryCounter)).round(), 600);
    print('Waiting $waitTime seconds till next try');
    return new Future.delayed(new Duration(seconds: waitTime), () {
      print('waited $waitTime seconds');
      return true;
    });
  })
  .then(print)
  .catchError(print);
}

Solution

  • You can use the plugin shared_preferences to save each HTTP response to the device until the upload completes successfully. Like this:

    requests: [
      {
        id: 8eh1gc,
        request: "..."
      },
      ...
    ],
    
    

    Then whenever the app is launched, check if any requests are in the list, retry them, and delete them if they complete. You could also use the background_fetch to do this every 15 minutes.