Skip to content

feat(linux): workmanager_linux — systemd-based background execution (fixes #324) - #716

Draft
ened wants to merge 3 commits into
mainfrom
feat/linux-port
Draft

feat(linux): workmanager_linux — systemd-based background execution (fixes #324)#716
ened wants to merge 3 commits into
mainfrom
feat/linux-port

Conversation

@ened

@ened ened commented Aug 3, 2026

Copy link
Copy Markdown
Collaborator

Summary

Implements the Linux desktop port for flutter_workmanager (fixes #324) as a
new federated package, workmanager_linux, following the design in
docs/desktop-support.mdx (systemd user units). Pure Dart — no Pigeon, no
native code: scheduling drives systemctl --user / systemd-run --user
through an injectable ProcessRunner, so the whole test suite runs without
systemd.

What's implemented

  • One-off tasks — transient units via
    systemd-run --user --unit=workmanager-<hash> --on-active=<delay>
    (--no-block for immediate runs; --collect so finished units don't
    linger).
  • Periodic tasks — a .timer/.service pair written to
    ~/.config/systemd/user/: OnUnitActiveSec for the frequency,
    OnStartupSec for the initial delay, Persistent=true for
    WorkManager-style catch-up of runs missed while the system was off.
  • Headless execution — units launch the app binary
    (Platform.resolvedExecutable) with --background-task <taskName> --payload <path>. The app's main() calls
    WorkmanagerLinux.maybeRunBackgroundTask(args, callbackDispatcher) which
    runs the dispatcher, invokes the handler and exits 0/1 (failed runs
    show up in the journal).
  • Payload persistence — Android-style on-disk inputData: JSON files
    under $XDG_DATA_HOME/workmanager/payloads/, named by a deterministic
    hash of the uniqueName (same hash derives unit names, so no registry is
    needed for query/cancel).
  • Full v1 API surfaceregisterOneOffTask, registerPeriodicTask,
    cancelByUniqueName, cancelAll, isScheduledByUniqueName,
    printScheduledTasks, plus WorkmanagerLinux.executeTask (mirrors
    WorkmanagerWeb.executeTask / workmanager_web's execution.dart
    registry pattern).
  • Core integration — Linux branch in workmanager_impl.dart platform
    selection, path dependency in workmanager/pubspec.yaml,
    workmanager_linux added to melos.yaml, docs page docs/linux.mdx +
    sidebar entry + README platform list.

Honest unsupported surface (v1)

  • Constraints (network/battery/charging): accepted, ignored. No
    gating in v1.
  • Backoff policy: accepted, ignored — failed one-off tasks are not
    retried; failed periodic tasks wait for the next interval.
  • existingWorkPolicy: effectively REPLACE; KEEP not implemented.
  • Tags: accepted but not tracked — cancelByTag throws
    UnsupportedError (needs a tag registry; cancel by unique name or
    cancelAll).
  • iOS-only task types (registerProcessingTask, health research,
    continued processing): UnsupportedError.
  • Frequency is honored as-is (no Android-style 15-minute floor).
  • Flatpak/Snap sandboxing unsupported (cannot write user units).

Headless dispatcher pattern

The dispatcher registers via WorkmanagerLinux.executeTask (a
WorkmanagerExecution-style registry mirroring workmanager_web), not
Workmanager().executeTask — the latter awaits a platform-channel handshake
that has no native counterpart on Linux and would fail in a headless process.

Testing

Pure Dart unit tests (no systemd): command construction (systemd-run args,
unit file contents, cancel/query commands) against a fake ProcessRunner,
payload round-trip, --background-task arg parsing, and the platform
implementation. melos run test, dart analyze and
dart format --set-exit-if-changed all pass locally (fvm, Flutter 3.44.8).

Note on the runner: the platform-level test file imports
WorkmanagerLinuxworkmanager_platform_interface → Flutter, which the
plain VM can't load (dart:ui), so the suite runs under flutter test
(like workmanager_web); the pure command/payload/runner tests also pass
under dart test.

Follow-ups (not in this PR)

  • feat!: BackgroundTaskResult enum instead of bool (fixes #23) #712 BackgroundTaskResult migration: this package implements the
    current Future<bool> main API, as do the other desktop/web packages; it
    will migrate to the enum with feat!: BackgroundTaskResult enum instead of bool (fixes #23) #712.
  • Parallel Windows PR: a separate PR adds a Platform.isWindows branch
    to the same _ensurePlatformImplementation block — expect a merge
    conflict in workmanager/lib/src/workmanager_impl.dart, that's fine.
  • workmanager/test/backward_compatibility_test.dart still expects a
    placeholder (UnimplementedError) on Linux test hosts; once both desktop
    branches land, that expectation should be updated (it passes unchanged on
    macOS/iOS/Android hosts).
  • workmanager_linux is a path: dependency of the publishable
    workmanager package for now (pub lint warning invalid_dependency); it
    should switch to ^0.1.0 once the package is released — the melos
    gitignored pubspec_overrides.yaml already wires the path locally.
  • CI wiring for dart test/flutter test in workmanager_linux (the
    melos test script already picks it up via flutter_test).

@docs-page

docs-page Bot commented Aug 3, 2026

Copy link
Copy Markdown

To preview the documentation for this pull request, visit the following URL:

docs.page/fluttercommunity/flutter_workmanager~716

Documentation is deployed and generated using docs.page

ened added 2 commits August 3, 2026 16:33
On Linux the platform initialize() now succeeds (workmanager_linux), so
the flow reaches _prepareInProcessExecution -> WorkmanagerFlutterApi.setUp,
which requires ServicesBinding. Ensure the binding like other tests do.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

add support to windows (flutter desktop)

1 participant