The flt_worker plugin allows you to schedule and execute Dart-written background tasks in a dedicated isolate, by utilizing the WorkManager API on Android, and the BackgroundTasks API on iOS 13.0+, respectively.

Background processing is suitable for time-consuming tasks like downloading/uploading offline data, fitting a machine learning model, etc. You can use this plugin to schedule work like that. A pre-registed Dart worker will be launched and run in the background whenever the system decides to run the task.

Add a dependency to pubspec.yaml :

dependencies: flt_worker: ^0.1.0

A worker is running in a separate instance of Flutter engine. Any plugins needed in the worker have to be registered again. In the following example, the path_provider plugin is registered for the background isolate.

iOS:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { [GeneratedPluginRegistrant registerWithRegistry:self]; // set a callback to register all plugins to a headless engine instance FltWorkerPlugin.registerPlugins = ^(NSObject<FlutterPluginRegistry> *registry) { [FLTPathProviderPlugin registerWithRegistrar:[registry registrarForPlugin:@"FLTPathProviderPlugin"]]; }; ... }

Android:

@Override public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) { GeneratedPluginRegistrant.registerWith(flutterEngine); // set a callback to register all plugins to a headless engine instance FltWorkerPlugin.registerPluginsForWorkers = registry -> { io.flutter.plugins.pathprovider.PathProviderPlugin.registerWith( registry.registrarFor("io.flutter.plugins.pathprovider.PathProviderPlugin")); return null; }; }

Fortunately, flt_worker itself is always available for the worker, so you don't have to register it again.

One more thing has to be done if you're working on iOS: all task identifiers must be registered before you can subimit any BGTaskRequest .

Add lines like this to the Info.plist file:

<key>BGTaskSchedulerPermittedIdentifiers</key> <array> <string>com.example.counter_task</string> <string>dev.example.task2</string> ... </array>

Initialization & work dispatcher #

Before you can schedule background tasks, a worker callback must be registerted to the plugin:

import 'package:flt_worker/flt_worker.dart'; void main() { runApp(MyApp()); initializeWorker(worker); }

Please notice that the callback must be a top-level or static function.

The worker function acts as a dispatcher of all background tasks, you can call different functions according to the payload of the work, and return a Future so that the plugin can notify the system scheduler whenever the work is done.

Future<void> worker(WorkPayload payload) { if (payload.tags.contains('download')) { return _fetchData(); } else if (...) { ... } else { return Future.value(); } } /// Cache data for offline use Future<void> _fetchData() async { // fetch data & update local storage }

Scheduling work #

You can use the enqueueWorkIntent function to schedule a background WorkIntent like this:

enqueueWorkIntent(WorkIntent( identifier: 'counter', initialDelay: Duration(seconds: 59), input: <String, dynamic>{ 'counter': counter, }, ));

The name of WorkIntent is chosen to avoid conflict with the term WorkRequest from the WorkManager API for Android.

Please see the documentation and also the example app to find out how to schedule different kinds of background work.

The background processing strategies and APIs are quite different on the Android and iOS platforms. The flt_worker plugin manages to provide a unified yet simplified API for general tasks, as the above example.

However, to leverage the full power of each platform's background processing features, you may consider the low-level platform-specific APIs.

For example, you can schedule a periodic work using the WorkManager APIs on an Android device:

import 'package:flt_worker/android.dart'; Future<void> _startPolling() async { await cancelAllWorkByTag('tag'); // cancel the previous work await enqueueWorkRequest(const PeriodicWorkRequest( repeatInterval: Duration(hours: 4), flexInterval: Duration(minutes: 5), tags: ['tag'], constraints: WorkConstraints( networkType: NetworkType.connected, storageNotLow: true, ), backoffCriteria: BackoffCriteria( policy: BackoffPolicy.linear, delay: Duration(minutes: 1), ), )); }

Or to use the BackgroundTasks APIs on iOS 13.0+:

import 'package:flt_worker/ios.dart'; void _increaseCounter(int counter) { submitTaskRequest(BGProcessingTaskRequest( 'com.example.counter_task', earliestBeginDate: DateTime.now().add(Duration(seconds: 10)), requiresNetworkConnectivity: false, requiresExternalPower: true, input: <String, dynamic>{ 'counter': counter, }, )); }

It's the very beginning of this library, some limitations you may need to notice are: