Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
35 changes: 35 additions & 0 deletions .github/workflows/generated-files.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
name: generated-files

on:
pull_request:
branches: [ main ]

jobs:
check-generated-files:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: subosito/flutter-action@v2
with:
channel: 'stable'
cache: true
- uses: bluefireteam/melos-action@v3

- name: Generate files
run: melos run generate

- name: Check for uncommitted changes
run: |
if ! git diff --quiet; then
echo "❌ Generated files are not up-to-date!"
echo "The following files have uncommitted changes after generation:"
git diff --name-only
echo ""
echo "Please run 'melos run generate' locally and commit the updated files."
echo ""
echo "Changes detected:"
git diff
exit 1
else
echo "✅ All generated files are up-to-date"
fi
18 changes: 14 additions & 4 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,24 @@
## Pre-Commit Requirements
**CRITICAL**: Always run from project root before ANY commit:
1. `ktlint -F .`
2. `find . -name "*.dart" ! -name "*.g.dart" ! -path "*/.*" -print0 | xargs -0 dart format --set-exit-if-changed`
3. `flutter test` (all Dart tests)
4. `cd example/android && ./gradlew :workmanager_android:test` (Android native tests)
1. `dart analyze` (check for code errors)
2. `ktlint -F .`
3. `find . -name "*.dart" ! -name "*.g.dart" ! -path "*/.*" -print0 | xargs -0 dart format --set-exit-if-changed`
4. `flutter test` (all Dart tests)
5. `cd example/android && ./gradlew :workmanager_android:test` (Android native tests)

## Code Generation
- Regenerate Pigeon files: `melos run generate:pigeon`
- Regenerate Dart files (including mocks): `melos run generate:dart`
- Do not manually edit *.g.* files

## Running Tests
- Use melos to run all tests: `melos run test`
- Or run tests in individual packages:
- `cd workmanager_android && flutter test`
- `cd workmanager_apple && flutter test`
- `cd workmanager && flutter test`
- Before running tests in workmanager package, ensure mocks are up-to-date: `melos run generate:dart`

## Test Quality Requirements
- **NEVER create useless tests**: No `assert(true)`, `expect(true, true)`, or compilation-only tests
- **Test real logic**: Exercise actual methods with real inputs and verify meaningful outputs
Expand Down
2 changes: 1 addition & 1 deletion example/integration_test/workmanager_integration_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ void main() {
requiresBatteryNotLow: false,
requiresCharging: true,
),
existingWorkPolicy: ExistingWorkPolicy.keep,
existingWorkPolicy: ExistingPeriodicWorkPolicy.keep,
backoffPolicy: BackoffPolicy.linear,
backoffPolicyDelay: const Duration(seconds: 10),
tag: 'periodic-tag',
Expand Down
69 changes: 69 additions & 0 deletions example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ const iOSBackgroundAppRefresh =
"dev.fluttercommunity.workmanagerExample.iOSBackgroundAppRefresh";
const iOSBackgroundProcessingTask =
"dev.fluttercommunity.workmanagerExample.iOSBackgroundProcessingTask";
const periodicUpdatePolicyTask =
"dev.fluttercommunity.workmanagerExample.periodicUpdatePolicyTask";

final List<String> allTasks = [
simpleTaskKey,
Expand All @@ -35,6 +37,7 @@ final List<String> allTasks = [
simplePeriodic1HourTask,
iOSBackgroundAppRefresh,
iOSBackgroundProcessingTask,
periodicUpdatePolicyTask,
];

// Pragma is mandatory if the App is obfuscated or using Flutter 3.1+
Expand Down Expand Up @@ -92,6 +95,11 @@ void callbackDispatcher() {
await Future<void>.delayed(Duration(seconds: 40));
print("$task finished");
break;
case periodicUpdatePolicyTask:
final frequency = inputData?['frequency'] ?? 'unknown';
print(
"$periodicUpdatePolicyTask executed with frequency: $frequency minutes at ${DateTime.now()}");
break;
default:
return Future.value(false);
}
Expand All @@ -110,6 +118,7 @@ class MyApp extends StatefulWidget {
class _MyAppState extends State<MyApp> {
bool workmanagerInitialized = false;
String _prefsString = "empty";
int _selectedFrequency = 15; // Default to 15 minutes

@override
Widget build(BuildContext context) {
Expand Down Expand Up @@ -244,6 +253,66 @@ class _MyAppState extends State<MyApp> {
}
: null),

SizedBox(height: 16),
Text(
"Test Periodic Task with UPDATE Policy (Android)",
style: Theme.of(context).textTheme.headlineSmall,
),
Text(
"Demonstrates issue #622 fix - changing frequency updates the existing task",
style: Theme.of(context).textTheme.bodySmall,
),
SizedBox(height: 8),
if (Platform.isAndroid) ...[
Row(
children: [
Text("Frequency: "),
Expanded(
child: DropdownButton<int>(
value: _selectedFrequency,
items: [
DropdownMenuItem(
value: 15, child: Text("15 minutes")),
DropdownMenuItem(
value: 30, child: Text("30 minutes")),
DropdownMenuItem(value: 60, child: Text("1 hour")),
],
onChanged: (value) {
setState(() {
_selectedFrequency = value!;
});
},
),
),
],
),
SizedBox(height: 8),
ElevatedButton(
child: Text("Register Periodic Task with UPDATE Policy"),
onPressed: () {
Workmanager().registerPeriodicTask(
periodicUpdatePolicyTask,
periodicUpdatePolicyTask,
frequency: Duration(minutes: _selectedFrequency),
initialDelay: Duration(seconds: 10),
existingWorkPolicy: ExistingPeriodicWorkPolicy.update,
inputData: <String, dynamic>{
'frequency': _selectedFrequency,
'timestamp': DateTime.now().toIso8601String(),
},
);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
"Registered periodic task with ${_selectedFrequency}min frequency using UPDATE policy"),
duration: Duration(seconds: 3),
),
);
},
),
],

SizedBox(height: 16),
// Currently we cannot provide frequency for iOS, hence it will be
// minimum 15 minutes after which iOS will reschedule
ElevatedButton(
Expand Down
2 changes: 0 additions & 2 deletions example/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@ dependencies:
dev_dependencies:
integration_test:
sdk: flutter
flutter_test:
sdk: flutter
flutter_lints: ^6.0.0

flutter:
Expand Down
14 changes: 10 additions & 4 deletions melos.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,19 @@ scripts:
get: melos exec -- dart pub get

test:
run: melos exec --depends-on="flutter_test" -- "flutter test"
run: melos exec -c 1 --depends-on="flutter_test" -- "flutter test"
description: Run tests for all packages with flutter_test dependency.

generate:
run: |
melos run generate:pigeon
melos run generate:dart
description: Generate all code (Pigeon files and Dart mocks/generated files).

generate:dart:
run: melos exec -c 1 --depends-on="build_runner" --no-flutter -- "dart run build_runner build --delete-conflicting-outputs"
run: melos exec -c 1 --depends-on="build_runner" -- "dart run build_runner build --delete-conflicting-outputs"
description: Build all generated files for Dart packages in this project.

generate:pigeon:
run: cd workmanager_platform_interface && dart run pigeon --input pigeons/workmanager_api.dart
description: Generate Pigeon type-safe platform channel code for workmanager_platform_interface.
run: melos exec -c 1 --depends-on="pigeon" -- "dart run pigeon --input pigeons/workmanager_api.dart"
description: Generate Pigeon type-safe platform channel code for packages with pigeon dependency.
8 changes: 8 additions & 0 deletions workmanager/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
# Future

## Breaking Changes
* **BREAKING**: Separate `ExistingWorkPolicy` and `ExistingPeriodicWorkPolicy` enums for better type safety and API clarity
* `registerPeriodicTask` now requires `ExistingPeriodicWorkPolicy` instead of `ExistingWorkPolicy`
* This mirrors Android's native WorkManager API design for better consistency

## Bug Fixes & Improvements
* Fix issue #622: Periodic tasks running at incorrect frequencies when re-registered with different intervals
* Changed default policy from `KEEP` to `UPDATE` for periodic tasks
* `UPDATE` policy ensures new task configurations replace existing ones without disruption
* Fix null cast to map bug in executeTask when inputData contains null keys or values (thanks to @Dr-wgy)
* Internal improvements to development and testing infrastructure

Expand Down
2 changes: 1 addition & 1 deletion workmanager/lib/src/workmanager_impl.dart
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ class Workmanager {
Map<String, dynamic>? inputData,
Duration? initialDelay,
Constraints? constraints,
ExistingWorkPolicy? existingWorkPolicy,
ExistingPeriodicWorkPolicy? existingWorkPolicy,
BackoffPolicy? backoffPolicy,
Duration? backoffPolicyDelay,
String? tag,
Expand Down
1 change: 1 addition & 0 deletions workmanager/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ dependencies:
dev_dependencies:
test: ^1.25.0
mockito: ^5.4.4
build_runner: ^2.4.9
get_it: ^8.0.0
flutter_test:
sdk: flutter
Expand Down
Loading
Loading