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>
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
}
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:
- It relies on the
BackgroundTasks
framework, which means it's not working on iOS before13.0
- For the Android platform, advanced features of
WorkManager
like Chaining Work are not yet supported