Schedule & run Dart code in the background on both Android & iOS

Overview

flt_worker

Pub Check Status MIT

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.

Integration

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>

Usage

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.

High-level vs. Low-level APIs

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,
    },
  ));
}

Limitations

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 before 13.0
  • For the Android platform, advanced features of WorkManager like Chaining Work are not yet supported
Comments
  • What should I do for iOS < 13?

    What should I do for iOS < 13?

    Hello,

    Thank you for the amazing plugin! I'm thinking about using it in my app to upload data to a server. There is a "background upload" plugin but I need to use client SSL certificates that this other plugin can't handle so a combination of your plugin and dio might save me.

    I still want to be able to install my app on iOS < 13, in which case it's fine if the upload doesn't happen in a background task.

    Is there a way to do this with you plugin? Or maybe just disable it for platforms < 13?

    Thanks for the help! I'm still new to flutter, sorry if that's a dumb question

    opened by julien-h 2
  • I got error when i am run my app

    I got error when i am run my app

    
    √  Built build\app\outputs\flutter-apk\app-debug.apk.
    E/AndroidRuntime(28338): FATAL EXCEPTION: pool-6-thread-1
    E/AndroidRuntime(28338): Process: com.astechtic.raksha, PID: 28338
    E/AndroidRuntime(28338): java.lang.IllegalArgumentException: com.astechtic.raksha: Targeting S+ (version 31 and above) requires that one of FLAG_IMMUTABLE or FLAG_MUTABLE be specified when creating a PendingIntent.
    E/AndroidRuntime(28338): Strongly consider using FLAG_IMMUTABLE, only use FLAG_MUTABLE if some functionality depends on the PendingIntent being mutable, e.g. if it needs to be used with inline replies or bubbles.
    E/AndroidRuntime(28338): 	at android.app.PendingIntent.checkFlags(PendingIntent.java:375)
    E/AndroidRuntime(28338): 	at android.app.PendingIntent.getBroadcastAsUser(PendingIntent.java:645)
    E/AndroidRuntime(28338): 	at android.app.PendingIntent.getBroadcast(PendingIntent.java:632)
    E/AndroidRuntime(28338): 	at androidx.work.impl.utils.ForceStopRunnable.getPendingIntent(ForceStopRunnable.java:196)
    E/AndroidRuntime(28338): 	at androidx.work.impl.utils.ForceStopRunnable.isForceStopped(ForceStopRunnable.java:128)
    E/AndroidRuntime(28338): 	at androidx.work.impl.utils.ForceStopRunnable.run(ForceStopRunnable.java:93)
    E/AndroidRuntime(28338): 	at androidx.work.impl.utils.SerialExecutor$Task.run(SerialExecutor.java:91)
    E/AndroidRuntime(28338): 	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
    E/AndroidRuntime(28338): 	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
    E/AndroidRuntime(28338): 	at java.lang.Thread.run(Thread.java:920)
    
    opened by lkrjangid1 0
  • Register plugin from isolate

    Register plugin from isolate

    If I want to use another plugin that starts in isolate and auto register plugins(like foreground service), there is an issue. The problem is that flt_worker requires an activity and crashes on registration, which leads to registering only the plugins that was before it in the GeneratedPluginRegistrant The problem is here :

              final MethodChannel channel = new MethodChannel(registrar.messenger(), CHANNEL_NAME);
              channel.setMethodCallHandler(new FltWorkerPlugin(registrar.activity()));
    

    I have changed it manually on my side to :

        try {
              final MethodChannel channel = new MethodChannel(registrar.messenger(), CHANNEL_NAME);
              channel.setMethodCallHandler(new FltWorkerPlugin(registrar.activity()));
          } catch (Exception e) {
              Log.e("Error","FltWorkerPlugin.registerWith", e );
          }
    

    And now can see the crash in the logs, but is handled and GeneratedPluginRegistrant can continue with the other plugins. Also I don't use flt_worker from other isolates and above approach is saving me

    Btw, I haven't checked if your plugin really needs an activity? If not you can pass a context only. Bellow code does not log a crash when is started from another isolate and also works when I tested it in my app

      public static void registerWith(Registrar registrar) {
          try {
              final MethodChannel channel = new MethodChannel(registrar.messenger(), CHANNEL_NAME);
              channel.setMethodCallHandler(new FltWorkerPlugin(registrar.context()));
          } catch (Exception e) {
              Log.e("Error","FltWorkerPlugin.registerWith", e );
          }
      }
    
    opened by 2math 0
  • NetworkType

    NetworkType

    Hi, thanks for this great plugin!

    I'm currently testing the abilities with the example app and I'm noticing something strange with the NetworkTypes.

    When I set NetworkType.notRequired , the task is not executing until I enable the WiFi and connect to the router, like is set NetworkType.unmetered.

    If I set NetworkType.unmetered , the task is executing even if the WiFi is off and I'm connected on the mobile network only, like should be for NetworkType.connected.

    If I set NetworkType.connected, the task is executing even if the WiFi and Mobile data are off, like should be for NetworkType.notRequired.

    I'm testing with the example app on Pixel XL 3a - Android 11

    /// Enqueues a work request to update the counter. void _increaseCounter(int counter) { enqueueWorkIntent(WorkIntent( identifier: kTagCounterWork, constraints: WorkConstraints(networkType: NetworkType.connected), input: <String, dynamic>{ 'counter': counter, }, isProcessingTask: true, )); }

    [√] Flutter (Channel dev, 1.26.0-1.0.pre, on Microsoft Windows [Version 10.0.19041.985], locale bg-BG) • Flutter version 1.26.0-1.0.pre at C:\code\soft\flutter_sdk\flutter • Framework revision 63062a6443 (5 months ago), 2020-12-13 23:19:13 +0800 • Engine revision 4797b06652 • Dart version 2.12.0 (build 2.12.0-141.0.dev)

    [√] Android toolchain - develop for Android devices (Android SDK version 30.0.2) • Android SDK at C:/Users/x/AppData/Local/Android/Sdk • Platform android-30, build-tools 30.0.2 • ANDROID_HOME = C:/Users/x/AppData/Local/Android/Sdk • Java binary at: C:\code\soft\android-studio-ide-4.1.3\android-studio\jre\bin\java • Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b01) • All Android licenses accepted.

    [√] Chrome - develop for the web • Chrome at C:\Program Files (x86)\Google\Chrome\Application\chrome.exe

    [√] Android Studio (version 4.1.0) • Android Studio at C:\code\soft\android-studio-ide-4.1.3\android-studio • Flutter plugin can be installed from: https://plugins.jetbrains.com/plugin/9212-flutter • Dart plugin can be installed from: https://plugins.jetbrains.com/plugin/6351-dart • Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b01)

    [√] Connected device (3 available) • Pixel 3a XL (mobile) • 94DAX0DRW1 • android-arm64 • Android 11 (API 30) • Chrome (web) • chrome • web-javascript • Google Chrome 90.0.4430.212 • Edge (web) • edge • web-javascript • Microsoft Edge 90.0.818.62

    • No issues found!

    opened by 2math 2
  • null-safety

    null-safety

    It would be greatly appreciated if we could get a updated null-safe version of the library, I will contribute a pull request with the necessary migrations.

    opened by bjartebore 0
  • use string instead of index for serializing constraint enum

    use string instead of index for serializing constraint enum

    This fixes a bug where the wrong NetworkType was used. This is because the NetworkType enum apparently has a different order in code than in the docs.

    opened by joharei 0
Releases(v0.1.0)
Owner
Yingxin Wu
Software engineer, swimmer, scuba diver
Yingxin Wu
A Flutter plugin to get location updates in the background for both Android and iOS

Background Location A Flutter plugin to get location updates in the background for both Android and iOS (Requires iOS 10.0+). Uses CoreLocation for iO

Ali Almoullim 181 Jan 4, 2023
Flutter Navigation - all types of navigation in flutter run main.tabBar.dart to see tabBar, and run main.dart to see the otheres

pop_up_bar A new Flutter project. Getting Started This project is a starting point for a Flutter application. A few resources to get you started if th

Michael Odumosu 0 Jan 1, 2022
A Flutter plugin which allows you to execute code in the background on Android and iOS.

Flutter Workmanager Flutter WorkManager is a wrapper around Android's WorkManager, iOS' performFetchWithCompletionHandler and iOS BGAppRefreshTask, ef

Flutter Community 699 Jan 5, 2023
This project was writed with pure dart code,which means it's support both iOS and Android.

This project was writed with pure dart code,which means it's support both iOS and Android. Screenshot Todo show/hide animation Usage You can find the

吴述军 Brant 377 Dec 24, 2022
🎬 A movie catalog app for both Android & IOS ~ Flutter.io project in Dart | Dart, Bloc, Movies

Movie Catalog App ?? Browse through movies from the YIFY api Getting Started For help getting started with Flutter, view our online documentation. Tod

Jonas De Vrient 49 Nov 21, 2022
Helper app to run code on Aliucord iOS via websocket.

aliucordebug A new Flutter project. Getting Started This project is a starting point for a Flutter application. A few resources to get you started if

Zoey 2 Jan 25, 2022
An E-Commerce application developed on Flutter, which helps to run the app on Android / IOS / Windows's OS / MacOS / Web Browser from a single codebase

BuySmart An E-Commerce application developed on Flutter, which helps to run the app on Android / IOS / Windows's OS / MacOS / Web Browser from a singl

Sumit Kumar 11 Oct 10, 2022
This is an application that uses the Flutter framework, SQFLite as a database to record blood pressure, blood sugar, BMI, or create medication reminders in multi mobile platforms You can run this project on iOS, Android

This is an application that uses the Flutter framework, SQFLite as a database to record blood pressure, blood sugar, BMI, or create medication reminders in multi mobile platforms You can run this project on iOS, Android

null 14 Dec 29, 2022
Win32 runner - Run a Flutter app without needing a lick of C/C++ code. Just Dart

Experimental package for running Flutter apps from a Dart runner, instead of the

Tim Sneath 51 Sep 25, 2022
A flutter plugin about qr code or bar code scan , it can scan from file、url、memory and camera qr code or bar code .Welcome to feedback your issue.

r_scan A flutter plugin about qr code or bar code scan , it can scan from file、url、memory and camera qr code or bar code .Welcome to feedback your iss

PengHui Li 112 Nov 11, 2022
Push Notification service for anime episodes and news. The episode updates will be based on actual upload on the internet and NOT Japan tv schedule as other apps do.

Quantz Push Notification service for anime episodes and news. Features Sub and dub - get notified with latest anime episodes on the internet. Ongoing

null 18 Nov 21, 2022
Raden Saleh 53 Jul 27, 2023
Write iOS&Android Code using Dart. This package liberates you from redundant glue code and low performance of Flutter Channel.

Dart_Native Dart_Native operates as both a code generator tool and a bridge to communicate between Dart and native APIs. Replaces the low-performing F

DartNative 893 Jan 4, 2023
Flutter Local Notifications - Learn how to implement local notifications into both Android and iOS using flutter_local_notifications plugin.

Flutter Local Notifications Example Flutter Local Notifications - Learn how to implement local notifications into both Android and iOS using flutter_l

Sandip Pramanik 12 Nov 29, 2022
A Flutter Accident reporting App working in both iOS and Android

Flutter Accident Reporting App A Flutter Accident reporting App working in both iOS and Android.This project total size of all Dart files is 4714 bite

sk shamimul islam 32 Oct 13, 2022
A horoscope forecasting application for both Android and iOS

Zodoscope A Horoscope Forcasting Application Built with Flutter, for Android and iOS API used: http://horoscope-api.herokuapp.com/ Key Features All Zo

null 15 Sep 25, 2022
A Basic Currency Converter made for both iOS and Android using the flutter.io platform

FlutterCurrencyConverter A Basic Currency Converter made for both iOS and Android using the flutter.io platform This app uses the ExchangeRate-API for

Carlo Gabriel Villalon Tapales 40 Nov 23, 2022
💳 A Flutter package for making payments via credo central. Provides support for both Android and iOS

?? Credo Package for Flutter TODO: Put a short description of the package here that helps potential users know whether this package might be useful fo

Samuel Abada 0 Dec 26, 2021
Flutterbodydetection - A flutter plugin that uses MLKit on iOS/Android platforms to enable body pose and mask detection using Pose Detection and Selfie Segmentation APIs for both static images and live camera stream.

body_detection A flutter plugin that uses MLKit on iOS/Android platforms to enable body pose and mask detection using Pose Detection and Selfie Segmen

null 18 Dec 5, 2022