Flutter Workmanager

repository·main·Indexed 21 days ago

https://github.com/fluttercommunity/flutter_workmanager

A plugin for executing background tasks in Flutter applications across Android, iOS, macOS, and experimentally on Web. It supports one-off and periodic tasks for use cases such as data synchronization, file uploads, and database maintenance. Key features include Android foreground services for long-running tasks, task cancellation handlers on Android, and a federated architecture with platform-specific implementations like workmanager_android, workmanager_apple, and workmanager_web.

Tokens
24K
Snippets
62
Records
95
Agent score
75%

What's inside flutter_workmanager

  1. Execute Dart code in the background with Flutter Workmanager

    main

    Flutter Workmanager allows you to execute Dart code in the background even when the app is closed.

    Supported Platforms:

    • Android & iOS: Background execution even when the app is closed.
    • macOS: Tasks run while the app is running or backgrounded, provided the Mac is awake.
    • Web (Experimental): Supported via the workmanager_web package using Service Workers and Web Workers. Note that web support has specific limitations.

    Common Use Cases:

    • Syncing data from an API.
    • Uploading files in the background.
    • Cleaning up old data, files, or cache.
    • Fetching notifications.
    • Performing database maintenance.
  2. Overview of the Federated Architecture

    main

    The plugin is built using a federated architecture, separating the unified Dart API from the platform-specific implementations:

    • workmanager: The main package containing the unified API used by developers.
    • workmanager_android: The Android-specific implementation.
    • workmanager_apple: The implementation for iOS (BGTaskScheduler) and macOS (NSBackgroundActivityScheduler).
  3. Understand the platform capabilities of Flutter Workmanager

    main

    Flutter Workmanager supports multiple platforms, but features like task types, reliability, and constraints vary significantly.

    Platform Support Summary

    • Android: Full support. All WorkManager features (one-off, periodic, constraints) are available and reliable.
    • iOS: Full support via BGTaskScheduler. Includes registerPeriodicTask, registerProcessingTask, and registerHealthResearchTask. Note that tasks do not run after the app is terminated.
    • macOS: Partial support. One-off and periodic tasks run via NSBackgroundActivityScheduler only while the app is running/backgrounded. Constraints are ignored.
    • Web: Experimental. Uses Service Workers and Web Workers. Periodic tasks map to Periodic Background Sync (best-effort, ~12h minimum).
    • Windows/Linux: Not supported.

    Key Feature Differences

    FeatureAndroidiOSmacOSWeb
    One-off tasksReliable; survives restartsRuns while app is aliveBest-effort while runningBest-effort via Service Worker
    Periodic tasksReliable (15m min)Best-effort (usage-based)Best-effort (interval hint)Experimental (~12h min)
    Processing tasksNot supported✅ Supported (long work)Mapped to one-offNot supported
    Constraints✅ Supported❌ System-managed❌ Ignored❌ Not supported
    Execution after kill✅ Yes❌ No❌ No⚠️ Only via Service Worker wake-up
  4. Understand the Workmanager federated architecture

    main

    The workmanager plugin uses a federated architecture to provide a unified API across different platforms. When you add workmanager to your pubspec.yaml, the following packages are automatically included:

    • workmanager: The main package providing the unified Dart API.
    • workmanager_android: Android implementation using the Android WorkManager library.
    • workmanager_apple: iOS implementation using BGTaskScheduler and macOS implementation using NSBackgroundActivityScheduler.
    • workmanager_platform_interface: The shared interface that platform implementations must follow.
  5. Troubleshoot background tasks stopping after app close

    main

    If background tasks stop running when the app is closed, it is usually due to Operating System scheduling rather than a plugin bug.

    Android Behavior

    WorkManager schedules persistent deferred work. Aggressive OEM battery managers (Xiaomi, Huawei, Samsung, etc.) and Android Doze mode often defer or block execution until the next app launch. No plugin can override these OEM battery managers.

    iOS Behavior

    If a user explicitly terminates an app (e.g., swiping it away), no background work will run until the app is relaunched. BGTaskScheduler tasks only run when iOS decides to relaunch the app, and processing tasks specifically require the device to be idle.

  6. How the hook-based debug system works

    main

    The Workmanager plugin provides a hook-based debug system that allows you to intercept and customize how debug information (like task status updates and exceptions) is handled on a per-platform basis.

    To use it, you first initialize Workmanager in your Flutter code without debug parameters, and then configure a platform-specific debug handler in your native Android (Application class) or iOS (AppDelegate) code.

    // 1. Initialize in Flutter
    await Workmanager().initialize(callbackDispatcher);
    
    // 2. Then set up platform-specific handlers in native code (see specific guides)
  7. Determine task behavior based on Dart return values

    main

    The outcome of your background task depends on the value returned by your Dart function. Note that Android and iOS handle false returns differently.

    Android Behavior

    Dart ReturnTask StatusSystem Behavior
    trueCompletedTask succeeds, won't retry
    falseRescheduledWorkManager schedules retry with backoff
    Future.error()FailedTask fails permanently, no retry
    Exception thrownFailedTask fails permanently, no retry

    iOS Behavior

    Dart ReturnTask StatusSystem Behavior
    trueCompletedTask succeeds, won't retry
    falseRetryingApp must manually reschedule
    Future.error()FailedTask fails, no automatic retry
    Exception thrownFailedTask fails, no automatic retry
  8. How Web background execution works in Workmanager

    main

    Experimental web support uses a workmanager_web package to approximate background execution. Because browsers cannot run a full Dart isolate or Flutter engine inside a Service Worker, the plugin uses different strategies depending on the app state:

    • When the page is open: Tasks run in a dedicated Web Worker executing a compiled, Flutter-free callback dispatcher (via dart2js) for real parallel execution.
    • When the page is closed (Periodic Background Sync - Chromium only): If the PWA is installed and has user engagement, Chrome wakes the Service Worker roughly every max(frequency, 12h). The Service Worker runs the compiled Dart dispatcher using importScripts and records results in IndexedDB.
    • When the page is closed (Web Push): A push message wakes the Service Worker to trigger the execution path (server-initiated).
    • When the page is closed (Fetch interception): An opportunistic, best-effort wake mechanism.

    Results from these background executions are replayed into the app's log upon the next page load.

  9. How workmanager_web handles background execution

    main

    workmanager_web uses different mechanisms depending on whether the application page is open or closed:

    SituationMechanismDetails
    Page openWeb WorkerTasks run in a dedicated Web Worker using the compiled (Flutter-free) dispatcher for real parallel execution off the main thread.
    Page closed (Periodic Sync)Service WorkerChromium fires the Service Worker (roughly every 12 hours for installed PWAs). The Service Worker runs the compiled Dart dispatcher via importScripts and records results in IndexedDB.
    Page closed (Web Push)Service WorkerA push message wakes the Service Worker to trigger the Dart execution path. Requires a push server.
    Page closed (Fetch Interception)Service WorkerOpportunistic wake-up via same-origin requests. Not reliable due to browser throttling.

    Results from executions that occurred while the page was closed are recorded in IndexedDB and replayed into the app's backgroundEvents stream when the page is next loaded.

  10. How task status states work

    main

    Background tasks transition through several states during their lifecycle. Monitoring these states via debug handlers allows you to track the progress of your background work.

    Task Status States

    StatusDescriptionWhen it occurs
    ScheduledTask has been scheduled with the systemWhen registerOneOffTask() or registerPeriodicTask() is called
    StartedTask execution has begun (first attempt)When task starts running for the first time
    RetryingTask is being retried after a previous attemptWhen task starts running after runAttemptCount > 0 (Android only)
    RescheduledTask will be retried laterWhen Dart function returns false (Android only)
    CompletedTask finished successfullyWhen Dart function returns true
    FailedTask failed permanentlyWhen Dart function throws an exception
    CancelledTask was cancelled before completionWhen cancelAll() or cancelByUniqueName() is called
  11. How to approximate periodic work on iOS

    main

    iOS does not have a fixed-interval scheduler. registerPeriodicTask is treated as a BGAppRefreshTaskRequest, where the frequency parameter is ignored. The system decides when and if the task runs based on usage patterns.

    To achieve more predictable intervals, use Task Chaining: schedule the next run from inside the current task's callback. This ensures the next link is submitted to the BGTaskScheduler and survives app relaunches.

    Chaining Characteristics:

    • Intervals are floors, not cadences: Intervals will drift and can stretch to hours.
    • Requires successful execution: The chain only advances when a link runs and re-submits. If the app is force-quit, the chain stalls.
    • App updates: Requests may not survive updates. It is recommended to re-seed the chain from your app's startup path (e.g., main).
    • Failure handling: Returning false from a task tells iOS the task failed, which may cause the system to defer future runs. Implement your own backoff by adjusting the initialDelay in the next scheduled task.
    @pragma('vm:entry-point')
    void callbackDispatcher() {
      Workmanager().executeTask((taskName, inputData) async {
        // ... do the work ...
    
        // Schedule the next run to maintain the chain
        Workmanager().registerPeriodicTask(
          "com.example.sync",
          "sync",
          initialDelay: Duration(hours: 1),
        );
        return true;
      });
    }