Skip to content

feat: 0.8.0 - Federated architecture migration with community bugfixes #611

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 52 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
e8f9d39
feat: Bugfix release 0.7.1 with multiple contributor fixes
ened Jun 24, 2025
6fbdff9
fix: Update Package.swift to remove archived flutter/engine dependency
ened Jun 24, 2025
e1b44b0
fix: Remove premature SPM implementation to avoid file duplication
ened Jun 24, 2025
fcb6452
feat: Migrate to federated plugin architecture for v0.8.0
ened Jun 24, 2025
6e39275
fix: Remove duplicated files and fix federated package issues
ened Jun 24, 2025
3621eb0
chore: Replace be.tramckrijte namespace with dev.fluttercommunity
ened Jun 24, 2025
6bfdf51
fix: Update GitHub Actions for federated architecture
ened Jun 24, 2025
6a7999b
fix: Restore Dart unit tests and fix generator issues
ened Jun 24, 2025
d32ab57
fix: Complete namespace migration and fix iOS module import
ened Jun 24, 2025
db90e79
style: Apply dart formatter to all packages
ened Jun 24, 2025
33614ba
fix: Remove ios_backup directory causing Swift lint failures
ened Jun 24, 2025
3ef530c
debug: Add detailed git diff output to format_dart workflow
ened Jun 24, 2025
ecaab1e
feat: Complete federated plugin architecture with comprehensive tests
ened Jun 24, 2025
844c27f
fix: Simplify format_dart CI check to properly detect formatting issues
ened Jun 24, 2025
0e8bbfc
fix: Add flutter pub get before dart format to resolve dependencies
ened Jun 24, 2025
fa90c25
feat: Update pubspec files for publishable packages
ened Jun 24, 2025
d35e4d4
fix: Add melos bootstrap to analysis workflow and fix example dependency
ened Jun 24, 2025
96f16d7
fix: Make initialDelaySeconds optional in iOS registerOneOffTask
ened Jun 24, 2025
b14ae1c
remove version in example/pubspec
ened Jun 24, 2025
1f3d7e5
fix dart not found
ened Jun 24, 2025
27e94ce
feat: Add LICENSE and README files for all published packages
ened Jun 24, 2025
6de804f
fix: Improve federated plugin documentation and melos CI setup
ened Jun 24, 2025
f26832c
fix: Resolve drive_android test failures and integration test logic e…
ened Jun 24, 2025
24714c7
fix: Replace melos bootstrap with manual dependency resolution in ana…
ened Jun 24, 2025
c38f5ea
fix: Replace manual melos setup with official melos-action
ened Jun 24, 2025
64999b6
debug: Add comprehensive debugging to analysis workflow
ened Jun 24, 2025
3f3e018
fix: Update analysis workflow for federated plugin architecture
ened Jun 25, 2025
fc18018
docs: Add CHANGELOG.md files to all federated plugin packages
ened Jun 25, 2025
994e80e
fix: only run pub publish analysis for now
ened Jun 25, 2025
20e6632
chore: Upgrade to Flutter 3.32 and flutter_lints 6.0.0
ened Jun 25, 2025
e4867b3
chore: Update Android emulator tests to use API level 35
ened Jun 25, 2025
846f8ac
fix: Fix Android test compilation issues
ened Jun 25, 2025
d4d838a
fix: do not double build
ened Jun 25, 2025
4b70405
fix: Correct native Android test command in CI
ened Jun 25, 2025
5df937e
chore: Remove test_pana folder
ened Jun 25, 2025
a8a8dd5
Revert "fix: do not double build"
ened Jun 25, 2025
7ef8194
fix: Handle missing isInDebugMode parameter in Android task registration
ened Jun 25, 2025
07ba57f
perf: Add Android emulator caching to improve CI performance
ened Jun 25, 2025
2d89760
try in one line
ened Jun 25, 2025
cd19b48
fix: Handle inputData Map properly and add comprehensive integration …
ened Jun 25, 2025
94be83b
refactor: Remove JSON conversion and use native Map transfer
ened Jun 25, 2025
5020f6a
fix: iOS compilation error and remove verbose flags
ened Jun 25, 2025
2f2b0a7
fix: Update enum values to camelCase for Dart conventions
ened Jun 25, 2025
662d4ba
fix: Resolve iOS build failure and integration test method names
ened Jun 25, 2025
0fa0f3b
style: Apply dart format to ensure consistent code style
ened Jun 25, 2025
7183db1
style: Apply ktlint formatting to Kotlin code
ened Jun 25, 2025
b371433
fix: Remove accidentally committed ktlint binary
ened Jun 25, 2025
17d4f22
fix: Add enum mapping for camelCase Dart values to Android enum names
ened Jun 25, 2025
1dfddf4
style: Apply ktlint formatting to when statement indentation
ened Jun 25, 2025
7d67007
fix: Separate expedited job test from regular constraint test
ened Jun 25, 2025
920c80e
docs: Update CHANGELOGs and READMEs for v0.8.0 release
ened Jun 25, 2025
cfa147f
fix: Improve input data handling and background channel initialization
ened Jun 27, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 22 additions & 4 deletions .github/workflows/analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,28 @@ on: pull_request
jobs:
package-analysis:
runs-on: ubuntu-latest
strategy:
matrix:
package: [workmanager, workmanager_platform_interface, workmanager_android, workmanager_ios]
steps:
- uses: actions/checkout@v4
- uses: axel-op/dart-package-analyzer@v3
- uses: subosito/flutter-action@v2
with:
# Required:
githubToken: ${{ secrets.GITHUB_TOKEN }}
relativePath: workmanager/
channel: "stable"
cache: true
- uses: bluefireteam/melos-action@v3

# unused until https://github.com/dart-lang/pana/issues/1020 is fixed
# # Only run dart-package-analyzer on the main workmanager package
# # The platform-specific packages are not meant to be published individually
# - uses: axel-op/dart-package-analyzer@v3
# if: matrix.package == 'workmanager'
# with:
# githubToken: ${{ secrets.GITHUB_TOKEN }}
# relativePath: ${{ matrix.package }}/

- name: Analyze package
run: |
cd ${{ matrix.package }}
flutter analyze
dart pub publish --dry-run
15 changes: 9 additions & 6 deletions .github/workflows/format.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ jobs:
channel: 'stable'
- name: Format
run: |
flutter pub get
dart format --set-exit-if-changed .

format_kotlin:
Expand Down Expand Up @@ -45,12 +46,14 @@ jobs:
with:
channel: 'stable'

- uses: bluefireteam/melos-action@v3
- name: publish checks
run: |
dart pub global activate melos
melos bootstrap
cd workmanager
flutter pub get
cd workmanager_platform_interface
flutter pub publish -n
cd ../workmanager_android
flutter pub publish -n
cd ../workmanager_ios
flutter pub publish -n
flutter pub global activate tuneup
flutter pub global run tuneup check
cd ../workmanager
flutter pub publish -n
66 changes: 42 additions & 24 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,7 @@ jobs:
with:
channel: 'stable'
cache: true
- name: Install melos
run: dart pub global activate melos
- name: Bootstrap packages
run: melos bootstrap
- uses: bluefireteam/melos-action@v3
- name: Test
run: |
cd workmanager
Expand All @@ -32,10 +29,7 @@ jobs:
with:
channel: 'stable'
cache: true
- name: Install melos
run: dart pub global activate melos
- name: Bootstrap packages
run: melos bootstrap
- uses: bluefireteam/melos-action@v3
- name: Build iOS App
run: cd example && flutter build ios --debug --no-codesign
- name: Run native iOS tests
Expand All @@ -53,14 +47,11 @@ jobs:
with:
channel: 'stable'
cache: true
- name: Install melos
run: dart pub global activate melos
- name: Bootstrap packages
run: melos bootstrap
- uses: bluefireteam/melos-action@v3
- name: Build Android App
run: cd example && flutter build apk --debug
- name: Run native Android tests
run: cd example/android && ./gradlew :workmanager:test
run: cd example/android && ./gradlew :workmanager_android:test

drive_ios:
strategy:
Expand All @@ -78,10 +69,7 @@ jobs:
- uses: futureware-tech/simulator-action@v3
with:
model: '${{ matrix.device }}'
- name: Install melos
run: dart pub global activate melos
- name: Bootstrap packages
run: melos bootstrap
- uses: bluefireteam/melos-action@v3
# Run flutter integrate tests
- name: Run Flutter integration tests
run: cd example && flutter test integration_test/workmanager_integration_test.dart
Expand All @@ -93,7 +81,7 @@ jobs:
strategy:
#set of different configurations of the virtual environment.
matrix:
api-level: [34]
api-level: [35]
# api-level: [21, 29]
target: [default]
steps:
Expand All @@ -111,16 +99,46 @@ jobs:
with:
channel: 'stable'
cache: true
- name: Install melos
run: dart pub global activate melos
- name: Bootstrap packages
run: melos bootstrap
- name: Run Flutter Driver tests
- uses: bluefireteam/melos-action@v3

# Gradle cache for better performance
- name: Gradle cache
uses: gradle/actions/setup-gradle@v3

# AVD cache to speed up emulator startup
- name: AVD cache
uses: actions/cache@v4
id: avd-cache
with:
path: |
~/.android/avd/*
~/.android/adb*
key: avd-${{ matrix.api-level }}-${{ matrix.target }}-${{ runner.os }}

# Generate AVD snapshot for caching if not already cached
- name: Create AVD and generate snapshot
if: steps.avd-cache.outputs.cache-hit != 'true'
uses: reactivecircus/android-emulator-runner@v2
with:
api-level: ${{ matrix.api-level }}
target: ${{ matrix.target }}
arch: x86_64
force-avd-creation: false
emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
disable-animations: true
script: echo "Generated AVD snapshot"

# Run actual tests using cached AVD
- name: Run Flutter integration tests
uses: reactivecircus/android-emulator-runner@v2
with:
api-level: ${{ matrix.api-level }}
target: ${{ matrix.target }}
arch: x86_64
force-avd-creation: false
emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
disable-animations: true
disk-size: 6000M
heap-size: 600M
script: cd example && flutter test integration_test/workmanager_integration_test.dart
script: |
cd example && flutter test integration_test/workmanager_integration_test.dart
4 changes: 2 additions & 2 deletions IOS_SETUP.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ import workmanager
WorkmanagerPlugin.registerBGProcessingTask(withIdentifier: "task-identifier")

// Register a periodic task in iOS 13+
WorkmanagerPlugin.registerPeriodicTask(withIdentifier: "be.tramckrijte.workmanagerExample.iOSBackgroundAppRefresh", frequency: NSNumber(value: 20 * 60))
WorkmanagerPlugin.registerPeriodicTask(withIdentifier: "dev.fluttercommunity.workmanagerExample.iOSBackgroundAppRefresh", frequency: NSNumber(value: 20 * 60))
```

- Info.plist
Expand All @@ -49,7 +49,7 @@ WorkmanagerPlugin.registerPeriodicTask(withIdentifier: "be.tramckrijte.workmanag
<string>task-identifier</string>

<!-- Register a periodic task in iOS 13+ -->
<string>be.tramckrijte.workmanagerExample.iOSBackgroundAppRefresh</string>
<string>dev.fluttercommunity.workmanagerExample.iOSBackgroundAppRefresh</string>
</array>
```
> ⚠️ On iOS 13+, adding a `BGTaskSchedulerPermittedIdentifiers` key to the Info.plist for new `BGTaskScheduler` API disables the `performFetchWithCompletionHandler` and `setMinimumBackgroundFetchInterval`
Expand Down
55 changes: 48 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,24 +1,65 @@
# Flutter Workmanager

[![pub package](https://img.shields.io/pub/v/workmanager.svg)](https://pub.dartlang.org/packages/workmanager)
[![Build status](https://img.shields.io/cirrus/github/vrtdev/flutter_workmanager/master)](https://cirrus-ci.com/github/vrtdev/flutter_workmanager/)
=======
[![pub points](https://img.shields.io/pub/points/workmanager)](https://pub.dev/packages/workmanager/score)
[![likes](https://img.shields.io/pub/likes/workmanager)](https://pub.dev/packages/workmanager/score)
[![popularity](https://img.shields.io/pub/popularity/workmanager)](https://pub.dev/packages/workmanager/score)
[![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/fluttercommunity/flutter_workmanager/test.yml?branch=main&label=tests)](https://github.com/fluttercommunity/flutter_workmanager/actions)
[![license](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/fluttercommunity/flutter_workmanager/blob/main/LICENSE)

Flutter WorkManager is a wrapper around [Android's WorkManager](https://developer.android.com/topic/libraries/architecture/workmanager), [iOS' performFetchWithCompletionHandler](https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1623125-application) and [iOS BGAppRefreshTask](https://developer.apple.com/documentation/backgroundtasks/bgapprefreshtask), effectively enabling headless execution of Dart code in the background.

For iOS users, please watch this video on a general introduction to background processing: https://developer.apple.com/videos/play/wwdc2019/707 ( and old link for [Background execution demystified (WWDC 2020)](https://devstreaming-cdn.apple.com/videos/wwdc/2020/10063/3/2E1C3BA0-2643-4330-A5B2-3A9878453987/wwdc2020_10063_hd.mp4). All of the constraints discussed in the video also apply to this plugin.
For iOS users, please watch this video on a general introduction to background processing: https://developer.apple.com/videos/play/wwdc2019/707. All of the constraints discussed in the video also apply to this plugin.

This is especially useful to run periodic tasks, such as fetching remote data on a regular basis.

> This plugin was featured in this [Medium blogpost](https://medium.com/vrt-digital-studio/flutter-workmanager-81e0cfbd6f6e)

## Federated Plugin Architecture

This plugin uses a federated architecture, which means that the main `workmanager` package provides the API, while platform-specific implementations are in separate packages:

- **workmanager**: The main package that provides the unified API
- **workmanager_platform_interface**: The common platform interface
- **workmanager_android**: Android-specific implementation
- **workmanager_ios**: iOS-specific implementation

This architecture allows for better platform-specific optimizations and easier maintenance. When you add `workmanager` to your `pubspec.yaml`, the platform-specific packages are automatically included through the endorsed federated plugin system.

# Platform Setup

In order for background work to be scheduled correctly you should follow the Android and iOS setup first.

- [Android Setup](https://github.com/fluttercommunity/flutter_workmanager/blob/master/ANDROID_SETUP.md)
- [iOS Setup](https://github.com/fluttercommunity/flutter_workmanager/blob/master/IOS_SETUP.md)

## Publishing (For Maintainers)

This project uses a federated plugin architecture with multiple packages. To publish updates:

1. **Update versions** in all `pubspec.yaml` files:
- `workmanager/pubspec.yaml`
- `workmanager_platform_interface/pubspec.yaml`
- `workmanager_android/pubspec.yaml`
- `workmanager_ios/pubspec.yaml`

2. **Publish packages in order**:
```bash
# 1. Publish platform interface first
cd workmanager_platform_interface && dart pub publish

# 2. Publish platform implementations
cd ../workmanager_android && dart pub publish
cd ../workmanager_ios && dart pub publish

# 3. Publish main package last
cd ../workmanager && dart pub publish
```

3. **Update dependencies** in main package to point to pub.dev versions instead of path dependencies before publishing

4. **Tag the release** with the version number: `git tag v0.8.0 && git push origin v0.8.0`

# How to use the package?

See sample folder for a complete working example.
Expand Down Expand Up @@ -135,12 +176,12 @@ To use `registerPeriodicTask` first register the task in `Info.plist` and `AppDe

```objc
// Register a periodic task with 20 minutes frequency. The frequency is in seconds.
WorkmanagerPlugin.registerPeriodicTask(withIdentifier: "be.tramckrijte.workmanagerExample.iOSBackgroundAppRefresh", frequency: NSNumber(value: 20 * 60))
WorkmanagerPlugin.registerPeriodicTask(withIdentifier: "dev.fluttercommunity.workmanagerExample.iOSBackgroundAppRefresh", frequency: NSNumber(value: 20 * 60))
```

Then schedule the task from your App
```dart
const iOSBackgroundAppRefresh = "be.tramckrijte.workmanagerExample.iOSBackgroundAppRefresh";
const iOSBackgroundAppRefresh = "dev.fluttercommunity.workmanagerExample.iOSBackgroundAppRefresh";
Workmanager().registerPeriodicTask(
iOSBackgroundAppRefresh,
iOSBackgroundAppRefresh,
Expand All @@ -161,7 +202,7 @@ iOS might terminate any running background processing tasks when the user starts
For more information see [BGProcessingTask](https://developer.apple.com/documentation/backgroundtasks/bgprocessingtask)

```dart
const iOSBackgroundProcessingTask = "be.tramckrijte.workmanagerExample.iOSBackgroundProcessingTask";
const iOSBackgroundProcessingTask = "dev.fluttercommunity.workmanagerExample.iOSBackgroundProcessingTask";
Workmanager().registerProcessingTask(
iOSBackgroundProcessingTask,
iOSBackgroundProcessingTask,
Expand Down Expand Up @@ -249,7 +290,7 @@ Workmanager().registerOneOffTask("1", "simpleTask", tag: "tag");
## Existing Work Policy

Indicates the desired behaviour when the same task is scheduled more than once.
The default is `KEEP`
The default is `keep`

```dart
Workmanager().registerOneOffTask("1", "simpleTask", existingWorkPolicy: ExistingWorkPolicy.append);
Expand Down
3 changes: 3 additions & 0 deletions workmanager/analysis_options.yml β†’ analysis_options.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
include: package:flutter_lints/flutter.yaml

formatter:
page_width: 120

linter:
rules:
- public_member_api_docs
2 changes: 1 addition & 1 deletion example/android/gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#Fri May 30 01:37:19 JST 2025
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-all.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
2 changes: 1 addition & 1 deletion example/android/settings.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ pluginManagement {

plugins {
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
id "com.android.application" version '8.10.1' apply false
id "com.android.application" version '8.11.0' apply false
id "org.jetbrains.kotlin.android" version "2.1.0" apply false
}

Expand Down
Loading
Loading