Flutter Background task at midnight everyday to process and schedule notifications for said day

3,365

SOLUTION 1: android_alarm_manager is the best solution to schedule background tasks. But the only disadvantage is only support Android. Let's start:

After importing this plugin to your project as usual, add the following to your AndroidManifest.xml within the tags:

<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>

Next, within the tags, add:

<service
    android:name="io.flutter.plugins.androidalarmmanager.AlarmService"
    android:permission="android.permission.BIND_JOB_SERVICE"
    android:exported="false"/>
<receiver
    android:name="io.flutter.plugins.androidalarmmanager.AlarmBroadcastReceiver"
    android:exported="false"/>
<receiver
    android:name="io.flutter.plugins.androidalarmmanager.RebootBroadcastReceiver"
    android:enabled="false">
    <intent-filter>
        <action android:name="android.intent.action.BOOT_COMPLETED"></action>
    </intent-filter>
</receiver>
Then in Dart code add:

import 'package:android_alarm_manager/android_alarm_manager.dart';

void printHello() {
  final DateTime now = DateTime.now();
  final int isolateId = Isolate.current.hashCode;
  print("[$now] Hello, world! isolate=${isolateId} function='$printHello'");
}

main() async {
  final int helloAlarmID = 0;
  await AndroidAlarmManager.initialize();
  runApp(...);
  await AndroidAlarmManager.periodic(const Duration(minutes: 1), helloAlarmID, printHello);
}

If you want to schedule any task every day at a specific time, you need to do something like this:

if (Platform.isAndroid) {
   await AndroidAlarmManager.periodic(
      const Duration(hours: 24), //Do the same every 24 hours
      helloAlarmID, //Different ID for each alarm
      printHello,
      wakeup: true, //the device will be woken up when the alarm fires
      startAt: DateTime(DateTime.now().year, DateTime.now().month, DateTime.now().day, 5, 0), //Start whit the specific time 5:00 am
      rescheduleOnReboot: true, //Work after reboot
   );
}

If alarm callbacks will need access to other Flutter plugins, including the alarm manager plugin itself, it may be necessary to inform the background service how to initialize plugins depending on which Flutter Android embedding the application is using.

This is done by giving the AlarmService a callback to call the application's onCreate method.

In particular, its Application class is as follows:

public class Application extends FlutterApplication implements PluginRegistrantCallback {
    @Override
    public void onCreate() {
        super.onCreate();
        AlarmService.setPluginRegistrant(this);
    }

    @Override
    public void registerWith(PluginRegistry registry) {
        //add AndroidAlarmManagerPlugin plugin register  if you work with arlarm
        AndroidAlarmManagerPlugin.registerWith(registry.registrarFor("io.flutter.plugins.androidalarmmanager.AndroidAlarmManagerPlugin"));
    }
}

Which must be reflected in the application's AndroidManifest.xml. E.g.:

<application
        android:name=".Application"
        ...

SOLUTION 2: Cron is another best solution to schedule background tasks. Cron run tasks periodically at fixed times, dates or intervals. But the onliy disadvantage of corn is once the app kill, cron not working in background as expected.

A simple usage example:

import 'package:cron/cron.dart';

main() {
  var cron = new Cron();
  cron.schedule(new Schedule.parse('*/3 * * * *'), () async {
    print('every three minutes');
  });
  cron.schedule(new Schedule.parse('8-11 * * * *'), () async {
    print('between every 8 and 11 minutes');
  });
}

How to setup a cronjob in general: information

Test cronjob: crontab

Share:
3,365
Michael Johnston
Author by

Michael Johnston

Updated on December 24, 2022

Comments

  • Michael Johnston
    Michael Johnston over 1 year

    APPLICATION: Task reminders. The user creates a task and schedules when this task is due.

    This package flutter_local_notification allows me to schedule a future notification to the user when they create this task. Which is fine if I schedule one notification for when the task is due.

    However, if the user forgets to complete that task and the day has now past when the task was due (with the original notification been and gone). I would like the app to continue to notify the user that they haven't completed this task yet once every day, until they open the app to cancel the notification/mark the task as complete.

    I'm certain that others must have already created something like this, but I'm struggling to find clear solutions online so thought I would ask here and see peoples opinions on what would be best practice.

    Two solutions I can think of:


    Daily background task

    A background task to run once a day to check what tasks are due and overdue for that current day and then schedule a notification for some point later during that day.

    Series of events

    • At 00:00 every day the app runs a background task checking what tasks are due today
    • If a task is due today, or is overdue. Schedule notification for later that day.
    • If the app is never opened, this process of checking and sending notifications repeats everyday.

    Repeating notification everyday

    Example Task due on "Monday"

    Instead of having a background task run everyday. For this example task I'm thinking I could schedule a notification on the Monday, and at the same time also schedule a daily repeating notification for every day after (Tuesdays, Wednesday, Thursday...) indefinitely. Then if the user opens the app and completes the task, these repeating notifications are cancelled. If not, the user gets notified every day until they do.

    I think this method would work, but I want to avoid scheduling so many notifications in the future and only have "todays" notifications scheduled. As this app could potentially have lots of tasks created by the user.


    My flutter app is only running only on Android at the moment, but I don't want to rule out iOS. So ideally a method which works cross-platform.

    All the data is stored locally, so I can't have a backend completing the data checks and sending push notifications.

    Thoughts on the solutions to this problem?