### Build Android Example App Source: https://github.com/fluttercommunity/flutter_workmanager/blob/main/CLAUDE.md Build the debug version of the Android example application. This command should be run from the example directory. ```bash cd example && flutter build apk --debug ``` -------------------------------- ### Clone and Run Example Source: https://github.com/fluttercommunity/flutter_workmanager/blob/main/example/README.md Commands to download and execute the example project locally. ```bash git clone https://github.com/fluttercommunity/flutter_workmanager.git cd flutter_workmanager/example flutter run ``` -------------------------------- ### Build example application Source: https://github.com/fluttercommunity/flutter_workmanager/blob/main/CONTRIBUTING.md Commands to build the example application for debugging purposes. ```bash cd example flutter build apk --debug flutter build ios --debug --no-codesign ``` -------------------------------- ### Build iOS Example App Source: https://github.com/fluttercommunity/flutter_workmanager/blob/main/CLAUDE.md Build the debug version of the iOS example application without codesigning. This command should be run from the example directory. ```bash cd example && flutter build ios --debug --no-codesign ``` -------------------------------- ### Build Verification Commands Source: https://github.com/fluttercommunity/flutter_workmanager/blob/main/SPM_MIGRATION_PLAN.md Commands to verify the example app build for both dependency managers. ```bash flutter config --no-enable-swift-package-manager cd example && flutter build ios --debug --no-codesign ``` ```bash flutter config --enable-swift-package-manager cd example && flutter build ios --debug --no-codesign ``` -------------------------------- ### Install Workmanager Dependency Source: https://context7.com/fluttercommunity/flutter_workmanager/llms.txt Add the package to your pubspec.yaml file and fetch dependencies. ```yaml dependencies: workmanager: ^0.8.0 ``` ```bash flutter pub get ``` -------------------------------- ### Run Flutter Pub Get Source: https://github.com/fluttercommunity/flutter_workmanager/blob/main/docs/quickstart.mdx Execute this command in your terminal after updating pubspec.yaml to fetch the new dependency. ```bash flutter pub get ``` -------------------------------- ### Run Android Native Tests Source: https://github.com/fluttercommunity/flutter_workmanager/blob/main/CLAUDE.md Execute native Android tests for the workmanager_android module. Ensure you are in the example directory before running. ```bash cd example/android && ./gradlew :workmanager_android:test ``` -------------------------------- ### Tabs Component Syntax Source: https://github.com/fluttercommunity/flutter_workmanager/blob/main/CLAUDE.md Example syntax for using the Tabs and TabItem components from the docs.page library. Ensure both 'label' and 'value' props are included on TabItem. ```jsx Content here ``` -------------------------------- ### Add Comprehensive Task Logging Source: https://github.com/fluttercommunity/flutter_workmanager/blob/main/docs/debugging.mdx Implement detailed logging for task start, input data, duration, and stack traces to aid in debugging. ```dart @pragma('vm:entry-point') void callbackDispatcher() { Workmanager().executeTask((task, inputData) async { final startTime = DateTime.now(); print('🚀 Task started: $task'); print('📊 Input data: $inputData'); try { // Your task implementation final result = await performTask(task, inputData); final duration = DateTime.now().difference(startTime); print('✅ Task completed in ${duration.inSeconds}s'); return result; } catch (e, stackTrace) { final duration = DateTime.now().difference(startTime); print('❌ Task failed after ${duration.inSeconds}s: $e'); print('📋 Stack trace: $stackTrace'); return false; // Retry } }); } ``` -------------------------------- ### iOS Logging Debug Handler Setup Source: https://context7.com/fluttercommunity/flutter_workmanager/llms.txt Configure the logging debug handler in your AppDelegate for iOS to view background task execution in the Xcode console. Ensure the workmanager_apple library is imported. ```swift import workmanager_apple @main class AppDelegate: FlutterAppDelegate { override func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { // Option 1: Logging debug handler (visible in Xcode console) WorkmanagerDebug.setCurrent(LoggingDebugHandler()) return super.application(application, didFinishLaunchingWithOptions: launchOptions) } } ``` -------------------------------- ### Android Logging Debug Handler Setup Source: https://context7.com/fluttercommunity/flutter_workmanager/llms.txt Configure the logging debug handler in your Application class to view background task execution in adb logcat. Ensure the WorkmanagerDebug class is imported. ```kotlin import dev.fluttercommunity.workmanager.WorkmanagerDebug import dev.fluttercommunity.workmanager.LoggingDebugHandler class MyApplication : Application() { override fun onCreate() { super.onCreate() // Option 1: Logging debug handler (visible in adb logcat) WorkmanagerDebug.setCurrent(LoggingDebugHandler()) } } ``` -------------------------------- ### Pull Request Description Template Source: https://github.com/fluttercommunity/flutter_workmanager/blob/main/CLAUDE.md A template for describing changes in a pull request, including a summary and a section for breaking changes with before/after code examples. ```markdown ## Summary - Brief change description Fixes #123 ## Breaking Changes (if applicable) **Before:** `old code` **After:** `new code` ``` -------------------------------- ### iOS Notification Debug Handler Setup Source: https://context7.com/fluttercommunity/flutter_workmanager/llms.txt Configure the notification debug handler in your AppDelegate for iOS. This can be customized with a specific category identifier and thread identifier. ```swift import workmanager_apple @main class AppDelegate: FlutterAppDelegate { override func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { // Option 2: Notification debug handler // WorkmanagerDebug.setCurrent(NotificationDebugHandler()) // Option 3: Notification handler with custom category // WorkmanagerDebug.setCurrent(NotificationDebugHandler( // categoryIdentifier: "myAppDebugCategory", // threadIdentifier: "workmanager_debug_thread" // )) return super.application(application, didFinishLaunchingWithOptions: launchOptions) } } ``` -------------------------------- ### Android Notification Debug Handler Setup Source: https://context7.com/fluttercommunity/flutter_workmanager/llms.txt Configure the notification debug handler in your Application class. This requires notification permissions and can be customized with a specific channel ID and group key for Android 8.0+. ```kotlin import dev.fluttercommunity.workmanager.WorkmanagerDebug import dev.fluttercommunity.workmanager.NotificationDebugHandler class MyApplication : Application() { override fun onCreate() { super.onCreate() // Option 2: Notification debug handler (requires notification permissions) // WorkmanagerDebug.setCurrent(NotificationDebugHandler()) // Option 3: Notification handler with custom channel // val channelId = "MyAppDebugChannel" // if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { // val channel = NotificationChannel(channelId, "Debug", NotificationManager.IMPORTANCE_DEFAULT) // getSystemService(NotificationManager::class.java).createNotificationChannel(channel) // } // WorkmanagerDebug.setCurrent(NotificationDebugHandler( // channelId = channelId, // groupKey = "workmanager_debug_group" // )) } } ``` -------------------------------- ### BackoffPolicy: Exponential Retry Source: https://context7.com/fluttercommunity/flutter_workmanager/llms.txt Configure exponential backoff for retrying tasks that fail. The delay increases exponentially, starting from 30 seconds and potentially reaching up to 5 hours. ```dart import 'package:workmanager/workmanager.dart'; // Exponential backoff: 30s, 1m, 2m, 4m... up to 5 hours Workmanager().registerOneOffTask( "upload-task", "file_upload", backoffPolicy: BackoffPolicy.exponential, backoffPolicyDelay: Duration(seconds: 30), ); ``` -------------------------------- ### Run integration tests Source: https://github.com/fluttercommunity/flutter_workmanager/blob/main/CONTRIBUTING.md Commands to execute integration tests for iOS and Android platforms. ```bash # iOS integration tests melos run test:drive_ios # Android integration tests melos run test:drive_android ``` -------------------------------- ### Cancel task by unique name Source: https://context7.com/fluttercommunity/flutter_workmanager/llms.txt Stops a specific task from executing if it has not started yet. ```dart import 'package:workmanager/workmanager.dart'; // Cancel a specific task await Workmanager().cancelByUniqueName("sync-task-1"); // Example: Cancel upload task when user cancels action Future cancelUpload(String uploadTaskId) async { await Workmanager().cancelByUniqueName(uploadTaskId); print('Upload task cancelled: $uploadTaskId'); } ``` -------------------------------- ### Package.swift Configuration Source: https://github.com/fluttercommunity/flutter_workmanager/blob/main/SPM_MIGRATION_PLAN.md The manifest file defining the Swift package targets and resources. ```swift // swift-tools-version: 5.9 import PackageDescription let package = Package( name: "workmanager_apple", platforms: [ .iOS(.v14) ], products: [ .library(name: "workmanager_apple", targets: ["workmanager_apple"]) ], targets: [ .target( name: "workmanager_apple", resources: [.process("Resources")] ) ] ) ``` -------------------------------- ### Manage package versions Source: https://github.com/fluttercommunity/flutter_workmanager/blob/main/CONTRIBUTING.md Command to coordinate version bumps across all packages in the monorepo. ```bash # Bump versions across related packages melos version ``` -------------------------------- ### Run project tests Source: https://github.com/fluttercommunity/flutter_workmanager/blob/main/CONTRIBUTING.md Commands to execute unit, native, and integration tests across the monorepo. ```bash # All tests melos run test # Specific package tests cd workmanager_android && flutter test cd workmanager_apple && flutter test # Native tests cd example/android && ./gradlew :workmanager_android:test cd example/ios && xcodebuild test -workspace Runner.xcworkspace -scheme Runner ``` -------------------------------- ### Workmanager.cancelByUniqueName Source: https://context7.com/fluttercommunity/flutter_workmanager/llms.txt Cancels a specific scheduled task by its unique name. This stops the task from executing if it hasn't started yet. ```APIDOC ## Workmanager.cancelByUniqueName ### Description Cancels a specific scheduled task by its unique name. This stops the task from executing if it hasn't started yet. ### Method POST ### Endpoint `/workmanager/cancelByUniqueName` (Internal) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body - **uniqueName** (string) - Required - The unique name of the task to cancel. ### Request Example ```dart await Workmanager().cancelByUniqueName("sync-task-1"); // Example: Cancel upload task when user cancels action Future cancelUpload(String uploadTaskId) async { await Workmanager().cancelByUniqueName(uploadTaskId); print('Upload task cancelled: $uploadTaskId'); } ``` ### Response #### Success Response (200) Indicates the task cancellation request was processed. #### Response Example ```json { "status": "cancelled" } ``` ``` -------------------------------- ### Initialize Workmanager in main() Source: https://github.com/fluttercommunity/flutter_workmanager/blob/main/docs/quickstart.mdx Initialize the Workmanager plugin by calling `Workmanager().initialize()` with your callback dispatcher function in the `main` method. ```dart import 'package:flutter/foundation.dart'; void main() { Workmanager().initialize(callbackDispatcher); runApp(MyApp()); } ``` -------------------------------- ### Inspect Android Jobs via ADB Source: https://github.com/fluttercommunity/flutter_workmanager/blob/main/docs/debugging.mdx Use ADB commands to inspect, monitor, and force-run Android jobs during development. ```bash # View scheduled jobs adb shell dumpsys jobscheduler | grep yourapp # View detailed job info adb shell dumpsys jobscheduler yourapp # Force run job (debug only) adb shell cmd jobscheduler run -f yourapp JOB_ID ``` ```bash # Monitor WorkManager logs adb logcat | grep WorkManager # Monitor app background execution adb logcat | grep "yourapp" ``` ```bash # Check if your app is whitelisted from battery optimization adb shell dumpsys deviceidle whitelist # Check battery optimization status adb shell settings get global battery_saver_constants # Force device into idle mode (testing) adb shell dumpsys deviceidle force-idle ``` -------------------------------- ### BackoffPolicy: Linear Retry Source: https://context7.com/fluttercommunity/flutter_workmanager/llms.txt Implement linear backoff for task retries, where the delay increases by a fixed amount for each subsequent retry, starting from the specified initial delay. ```dart import 'package:workmanager/workmanager.dart'; // Linear backoff: 30s, 60s, 90s, 120s... Workmanager().registerOneOffTask( "sync-task", "data_sync", backoffPolicy: BackoffPolicy.linear, backoffPolicyDelay: Duration(seconds: 30), ); ``` -------------------------------- ### GitHub Actions Matrix Configuration Source: https://github.com/fluttercommunity/flutter_workmanager/blob/main/SPM_MIGRATION_PLAN.md YAML configuration for testing both CocoaPods and SPM build paths in CI. ```yaml strategy: matrix: spm_enabled: [true, false] include: - spm_enabled: true config_cmd: "flutter config --enable-swift-package-manager" name: "SPM" - spm_enabled: false config_cmd: "flutter config --no-enable-swift-package-manager" name: "CocoaPods" ``` -------------------------------- ### Run All Tests with Melos Source: https://github.com/fluttercommunity/flutter_workmanager/blob/main/CLAUDE.md Execute all tests across the project using Melos. This is the recommended way to run tests. ```bash melos run test ``` -------------------------------- ### Run Individual Package Tests Source: https://github.com/fluttercommunity/flutter_workmanager/blob/main/CLAUDE.md Run tests within a specific package. Navigate to the package directory first. ```bash cd workmanager_android && flutter test ``` ```bash cd workmanager_apple && flutter test ``` ```bash cd workmanager && flutter test ``` -------------------------------- ### Current iOS Directory Structure Source: https://github.com/fluttercommunity/flutter_workmanager/blob/main/SPM_MIGRATION_PLAN.md The existing file layout for the workmanager_apple plugin before migration. ```text workmanager_apple/ios/ ├── Assets/ ├── Classes/ │ ├── BackgroundTaskOperation.swift │ ├── BackgroundWorker.swift │ ├── Extensions.swift │ ├── LoggingDebugHandler.swift │ ├── NotificationDebugHandler.swift │ ├── SimpleLogger.swift │ ├── ThumbnailGenerator.swift │ ├── UserDefaultsHelper.swift │ ├── WMPError.swift │ ├── WorkmanagerDebugHandler.swift │ ├── WorkmanagerPlugin.swift │ └── pigeon/ │ └── WorkmanagerApi.g.swift ├── Resources/ │ └── PrivacyInfo.xcprivacy └── workmanager_apple.podspec ``` -------------------------------- ### Initialize Workmanager Source: https://github.com/fluttercommunity/flutter_workmanager/blob/main/docs/debugging.mdx Initialize the Workmanager plugin without debug parameters before setting up platform-specific handlers. ```dart await Workmanager().initialize(callbackDispatcher); ``` -------------------------------- ### Implement WorkmanagerPlatform Interface Source: https://github.com/fluttercommunity/flutter_workmanager/blob/main/workmanager_platform_interface/README.md To create a new platform-specific implementation of workmanager, extend the `WorkmanagerPlatform` class. This involves defining the platform-specific behavior for background task management. After implementation, register your custom platform instance by calling `WorkmanagerPlatform.instance = MyWorkmanagerPlatform()`. ```dart WorkmanagerPlatform.instance = MyWorkmanagerPlatform() ``` -------------------------------- ### Implement Task Callback Dispatcher Source: https://github.com/fluttercommunity/flutter_workmanager/blob/main/docs/task-status.mdx Defines the entry point for background tasks using the Workmanager executeTask method. ```dart @pragma('vm:entry-point') void callbackDispatcher() { Workmanager().executeTask((task, inputData) async { try { // Your task logic here final result = await performWork(task, inputData); if (result.isSuccess) { return true; // ✅ Task succeeded } else { return false; // 🔄 Retry with backoff (Android) or manual reschedule (iOS) } } catch (e) { // 🔥 Permanent failure - will not retry throw Exception('Task failed: $e'); } }); } ``` -------------------------------- ### Run SwiftLint Formatter Source: https://github.com/fluttercommunity/flutter_workmanager/blob/main/CLAUDE.md Apply SwiftLint formatting to Swift code files. The --fix flag attempts to automatically fix formatting issues. ```bash swiftlint --fix ``` -------------------------------- ### Run ktlint Formatter Source: https://github.com/fluttercommunity/flutter_workmanager/blob/main/CLAUDE.md Apply ktlint formatting to Kotlin code files. The -F flag attempts to automatically fix formatting issues. ```bash ktlint -F . ``` -------------------------------- ### Configure Task Constraints Source: https://github.com/fluttercommunity/flutter_workmanager/blob/main/docs/customization.mdx Define device conditions like network status or battery level that must be met for a task to execute. ```dart Workmanager().registerOneOffTask( "sync-task", "data_sync", constraints: Constraints( networkType: NetworkType.connected, // Require internet connection requiresBatteryNotLow: true, // Don't run when battery is low requiresCharging: false, // Can run when not charging requiresDeviceIdle: false, // Can run when device is active requiresStorageNotLow: true, // Don't run when storage is low ), ); ``` ```dart // Different network requirements NetworkType.connected // Any internet connection NetworkType.unmetered // WiFi or unlimited data only NetworkType.not_required // Can run without internet ``` ```dart constraints: Constraints( requiresBatteryNotLow: true, // Wait for adequate battery requiresCharging: true, // Only run when plugged in ) ``` -------------------------------- ### Configure iOS Debug Handlers Source: https://github.com/fluttercommunity/flutter_workmanager/blob/main/docs/debugging.mdx Set up logging or notification handlers in the AppDelegate to track background task execution on iOS. ```swift // In your AppDelegate.swift import workmanager_apple @main class AppDelegate: FlutterAppDelegate { override fun application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { WorkmanagerDebug.setCurrent(LoggingDebugHandler()) return super.application(application, didFinishLaunchingWithOptions: launchOptions) } } ``` ```swift WorkmanagerDebug.setCurrent(NotificationDebugHandler()) ``` -------------------------------- ### Configure iOS Periodic Tasks Source: https://context7.com/fluttercommunity/flutter_workmanager/llms.txt Set up periodic tasks with custom frequency in Info.plist and AppDelegate. ```xml UIBackgroundModes processing BGTaskSchedulerPermittedIdentifiers com.yourapp.periodic_task ``` ```swift import workmanager_apple // In application didFinishLaunching WorkmanagerPlugin.registerPeriodicTask( withIdentifier: "com.yourapp.periodic_task", frequency: NSNumber(value: 20 * 60) // 20 minutes (15 min minimum) ) ``` -------------------------------- ### Proposed SPM Directory Structure Source: https://github.com/fluttercommunity/flutter_workmanager/blob/main/SPM_MIGRATION_PLAN.md The target directory structure required for Swift Package Manager compliance. ```text workmanager_apple/ios/ ├── Sources/ │ └── workmanager_apple/ │ ├── include/ │ │ └── workmanager_apple-umbrella.h (if needed) │ └── [all .swift files moved here] └── Resources/ └── PrivacyInfo.xcprivacy ``` -------------------------------- ### Validate packages for publishing Source: https://github.com/fluttercommunity/flutter_workmanager/blob/main/CONTRIBUTING.md Commands to perform a dry-run validation to ensure packages are ready for publication. ```bash # Validate all packages are ready for publishing melos run publish:dry-run # Or for individual packages: cd workmanager && dart pub publish --dry-run cd workmanager_android && dart pub publish --dry-run cd workmanager_apple && dart pub publish --dry-run cd workmanager_platform_interface && dart pub publish --dry-run ``` -------------------------------- ### Configure iOS Info.plist for Background Fetch Source: https://github.com/fluttercommunity/flutter_workmanager/blob/main/docs/quickstart.mdx Add the 'fetch' background mode to your Info.plist file to enable Background Fetch for periodic tasks. ```xml UIBackgroundModes fetch ``` -------------------------------- ### Implement Workmanager Background Tasks Source: https://context7.com/fluttercommunity/flutter_workmanager/llms.txt The callback dispatcher must be a top-level function or static method annotated with @pragma('vm:entry-point'). It handles task execution logic and returns a boolean indicating success or failure for retry purposes. ```dart import 'dart:io'; import 'package:flutter/material.dart'; import 'package:workmanager/workmanager.dart'; import 'package:shared_preferences/shared_preferences.dart'; const simpleTaskKey = "com.example.simpleTask"; const periodicSyncKey = "com.example.periodicSync"; const fileUploadKey = "com.example.fileUpload"; @pragma('vm:entry-point') void callbackDispatcher() { Workmanager().executeTask((task, inputData) async { final prefs = await SharedPreferences.getInstance(); await prefs.reload(); print('Executing task: $task at ${DateTime.now()}'); print('Input data: $inputData'); try { switch (task) { case simpleTaskKey: // Simple one-off task await prefs.setString('lastSimpleTask', DateTime.now().toIso8601String()); print('Simple task completed'); break; case periodicSyncKey: // Periodic data sync await Future.delayed(Duration(seconds: 2)); // Simulate API call await prefs.setString('lastSync', DateTime.now().toIso8601String()); print('Periodic sync completed'); break; case fileUploadKey: final fileName = inputData?['fileName'] as String?; final attempt = inputData?['attempt'] ?? 1; if (attempt < 3) { print('Upload attempt $attempt for $fileName - simulating retry'); return Future.value(false); // Trigger retry } print('Upload succeeded for $fileName'); break; case Workmanager.iOSBackgroundTask: // iOS Background Fetch await prefs.setString('lastBackgroundFetch', DateTime.now().toIso8601String()); print('iOS background fetch completed'); break; default: print('Unknown task: $task'); return Future.value(false); } return Future.value(true); } catch (e) { print('Task failed with error: $e'); return Future.error(e); } }); } void main() { WidgetsFlutterBinding.ensureInitialized(); runApp(MyApp()); } class MyApp extends StatefulWidget { @override _MyAppState createState() => _MyAppState(); } class _MyAppState extends State { bool _initialized = false; Future _initializeWorkmanager() async { await Workmanager().initialize(callbackDispatcher); setState(() => _initialized = true); } @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( appBar: AppBar(title: Text('Workmanager Example')), body: ListView( padding: EdgeInsets.all(16), children: [ ElevatedButton( onPressed: _initializeWorkmanager, child: Text('Initialize Workmanager'), ), SizedBox(height: 16), ElevatedButton( onPressed: _initialized ? () { Workmanager().registerOneOffTask( simpleTaskKey, simpleTaskKey, initialDelay: Duration(seconds: 5), ); } : null, child: Text('Schedule One-Off Task'), ), ElevatedButton( onPressed: _initialized && Platform.isAndroid ? () { Workmanager().registerPeriodicTask( periodicSyncKey, periodicSyncKey, frequency: Duration(hours: 1), constraints: Constraints( networkType: NetworkType.connected, requiresBatteryNotLow: true, ), ); } : null, child: Text('Schedule Periodic Task (Android)'), ), ElevatedButton( onPressed: _initialized ? () { Workmanager().registerOneOffTask( fileUploadKey, fileUploadKey, inputData: { 'fileName': 'photo.jpg', 'attempt': 1, }, constraints: Constraints( networkType: NetworkType.connected, ), backoffPolicy: BackoffPolicy.exponential, ); } : null, child: Text('Schedule Upload Task'), ), SizedBox(height: 16), ElevatedButton( onPressed: _initialized ? () async { await Workmanager().cancelAll(); print('All tasks cancelled'); } : null, child: Text('Cancel All Tasks'), ), ], ), ), ); } } ``` -------------------------------- ### Configure iOS Info.plist for Periodic Tasks with Frequency Source: https://github.com/fluttercommunity/flutter_workmanager/blob/main/docs/quickstart.mdx Enable 'processing' background mode and list permitted identifiers in Info.plist for custom frequency periodic tasks. ```xml UIBackgroundModes processing BGTaskSchedulerPermittedIdentifiers com.yourapp.periodic_task ``` -------------------------------- ### Configure iOS BGTaskScheduler Processing Source: https://context7.com/fluttercommunity/flutter_workmanager/llms.txt Register processing tasks in Info.plist and the AppDelegate. ```xml UIBackgroundModes processing BGTaskSchedulerPermittedIdentifiers com.yourapp.processing_task ``` ```swift import workmanager_apple // In application didFinishLaunching WorkmanagerPlugin.registerBGProcessingTask( withIdentifier: "com.yourapp.processing_task" ) ``` -------------------------------- ### Run Flutter Tests Source: https://github.com/fluttercommunity/flutter_workmanager/blob/main/CLAUDE.md Execute all Dart tests within the Flutter project. This is a mandatory pre-commit check. ```bash flutter test ``` -------------------------------- ### Migrate Debug Initialization Source: https://github.com/fluttercommunity/flutter_workmanager/blob/main/docs/task-status.mdx Updates initialization logic by removing the deprecated isInDebugMode parameter in favor of platform-specific debug handlers. ```dart // ❌ Old approach (deprecated) await Workmanager().initialize( callbackDispatcher, isInDebugMode: true, // Deprecated ); // ✅ New approach await Workmanager().initialize(callbackDispatcher); // Set up platform-specific debug handler // Android: WorkmanagerDebug.setCurrent(NotificationDebugHandler()) // iOS: WorkmanagerDebug.setCurrent(LoggingDebugHandler()) ``` -------------------------------- ### Initialize and Register Background Tasks in Dart Source: https://github.com/fluttercommunity/flutter_workmanager/blob/main/workmanager/README.md Defines the callback dispatcher for background execution and initializes the Workmanager plugin in the main application entry point. ```dart @pragma('vm:entry-point') void callbackDispatcher() { Workmanager().executeTask((task, inputData) async { print("Background task: $task"); // Your background work here return Future.value(true); }); } void main() { Workmanager().initialize(callbackDispatcher); Workmanager().registerOneOffTask("task-id", "simpleTask"); runApp(MyApp()); } ``` -------------------------------- ### Schedule and Handle Tasks with Input Data Source: https://github.com/fluttercommunity/flutter_workmanager/blob/main/docs/customization.mdx Pass JSON-serializable data to background tasks and extract it within the callback dispatcher. ```dart // Schedule task with input data Workmanager().registerOneOffTask( "upload-task", "file_upload", inputData: { 'fileName': 'document.pdf', 'uploadUrl': 'https://api.example.com/upload', 'retryCount': 3, 'userId': 12345, }, ); // Access input data in your task @pragma('vm:entry-point') void callbackDispatcher() { Workmanager().executeTask((task, inputData) async { print('Task: $task'); print('Input: $inputData'); // Extract specific values String? fileName = inputData?['fileName']; String? uploadUrl = inputData?['uploadUrl']; int retryCount = inputData?['retryCount'] ?? 0; int userId = inputData?['userId'] ?? 0; // Use the data in your task logic await uploadFile(fileName, uploadUrl, userId); return Future.value(true); }); } ``` -------------------------------- ### Configure Android Notification Debugging Source: https://github.com/fluttercommunity/flutter_workmanager/blob/main/docs/task-status.mdx Set up `NotificationDebugHandler` with custom channel ID and group key for Android. Ensure the notification channel is created if using a custom ID. ```kotlin // NotificationDebugHandler - shows status as notifications WorkmanagerDebug.setCurrent(NotificationDebugHandler()) ``` ```kotlin // Custom notification channel and grouping (you must create the channel first) val channelId = "MyAppDebugChannel" if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { val channel = NotificationChannel(channelId, "My App Debug", NotificationManager.IMPORTANCE_DEFAULT) val notificationManager = getSystemService(NotificationManager::class.java) notificationManager.createNotificationChannel(channel) } WorkmanagerDebug.setCurrent(NotificationDebugHandler( channelId = channelId, groupKey = "workmanager_debug_group" )) ``` ```kotlin // LoggingDebugHandler - writes to system log WorkmanagerDebug.setCurrent(LoggingDebugHandler()) ``` ```kotlin // Custom handler class CustomDebugHandler : WorkmanagerDebug() { override fun onTaskStatusUpdate( context: Context, taskInfo: TaskDebugInfo, status: TaskStatus, result: TaskResult? ) { when (status) { TaskStatus.SCHEDULED -> log("Task scheduled: ${taskInfo.taskName}") TaskStatus.STARTED -> log("Task started: ${taskInfo.taskName}") TaskStatus.RETRYING -> log("Task retrying (attempt ${taskInfo.runAttemptCount}): ${taskInfo.taskName}") TaskStatus.RESCHEDULED -> log("Task rescheduled: ${taskInfo.taskName}") TaskStatus.COMPLETED -> log("Task completed: ${taskInfo.taskName}") TaskStatus.FAILED -> log("Task failed: ${taskInfo.taskName}, error: ${result?.error}") TaskStatus.CANCELLED -> log("Task cancelled: ${taskInfo.taskName}") } } } ``` -------------------------------- ### Configure Android Debug Handlers Source: https://github.com/fluttercommunity/flutter_workmanager/blob/main/docs/debugging.mdx Set up logging or notification handlers within the Android Application class to monitor background tasks. ```kotlin // In your Application class import dev.fluttercommunity.workmanager.WorkmanagerDebug import dev.fluttercommunity.workmanager.LoggingDebugHandler class MyApplication : Application() { override fun onCreate() { super.onCreate() WorkmanagerDebug.setCurrent(LoggingDebugHandler()) } } ``` ```kotlin import dev.fluttercommunity.workmanager.NotificationDebugHandler class MyApplication : Application() { override fun onCreate() { super.onCreate() WorkmanagerDebug.setCurrent(NotificationDebugHandler()) } } ``` -------------------------------- ### Configure iOS Info.plist for Processing Tasks Source: https://github.com/fluttercommunity/flutter_workmanager/blob/main/docs/quickstart.mdx Add 'processing' to UIBackgroundModes and specify permitted task identifiers in Info.plist for BGTaskScheduler. ```xml UIBackgroundModes processing BGTaskSchedulerPermittedIdentifiers com.yourapp.processing_task ``` -------------------------------- ### Schedule One-time and Periodic Tasks Source: https://github.com/fluttercommunity/flutter_workmanager/blob/main/docs/customization.mdx Configure tasks with initial delays or recurring frequencies. ```dart // One-time task with delay Workmanager().registerOneOffTask( "delayed-task", "cleanup", initialDelay: Duration(minutes: 30), inputData: {'cleanupType': 'cache'} ); // Periodic task with custom frequency Workmanager().registerPeriodicTask( "hourly-sync", "data_sync", frequency: Duration(hours: 1), // Android: minimum 15 minutes initialDelay: Duration(minutes: 5), // Wait before first execution inputData: {'syncType': 'incremental'} ); ``` -------------------------------- ### Manage Resources in Background Isolates Source: https://github.com/fluttercommunity/flutter_workmanager/blob/main/docs/customization.mdx Initialize and clean up resources like `HttpClient` within the background task callback to ensure they are properly managed in the separate isolate. ```dart @pragma('vm:entry-point') void callbackDispatcher() { Workmanager().executeTask((task, inputData) async { HttpClient? client; try { // Initialize resources in the background isolate client = HttpClient(); // Perform task await performNetworkOperation(client); return Future.value(true); } finally { // Clean up resources client?.close(); } }); } ``` -------------------------------- ### Schedule One-Time and Periodic Tasks Source: https://github.com/fluttercommunity/flutter_workmanager/blob/main/docs/quickstart.mdx Schedule tasks using `registerOneOffTask` for a single execution or `registerPeriodicTask` for recurring execution. Specify unique IDs, task names, and optional delays or frequencies. ```dart // Schedule a one-time task Workmanager().registerOneOffTask( "sync-task", "data_sync", initialDelay: Duration(seconds: 10), ); // Schedule a periodic task Workmanager().registerPeriodicTask( "cleanup-task", "cleanup", frequency: Duration(hours: 24), ); ``` -------------------------------- ### Dart Code Formatting Source: https://github.com/fluttercommunity/flutter_workmanager/blob/main/CLAUDE.md Format Dart files in the project, excluding generated files and hidden directories. This command ensures consistent code style. ```bash find . -name "*.dart" ! -name "*.g.dart" ! -path "*/.*" -print0 | xargs -0 dart format --set-exit-if-changed ``` -------------------------------- ### Define background task handler Source: https://context7.com/fluttercommunity/flutter_workmanager/llms.txt Registers the callback dispatcher to process scheduled tasks. Must be annotated with @pragma('vm:entry-point'). ```dart import 'package:workmanager/workmanager.dart'; @pragma('vm:entry-point') void callbackDispatcher() { Workmanager().executeTask((task, inputData) async { final startTime = DateTime.now(); print('Task started: $task at $startTime'); print('Input data: $inputData'); try { switch (task) { case 'photo_upload': final fileName = inputData?['fileName'] as String?; final uploadUrl = inputData?['uploadUrl'] as String?; await uploadPhoto(fileName!, uploadUrl!); break; case 'data_sync': final syncType = inputData?['syncType'] ?? 'full'; await performDataSync(syncType); break; case 'cache_cleanup': final maxAgeHours = inputData?['maxAgeHours'] ?? 24; await cleanupCache(maxAgeHours); break; case Workmanager.iOSBackgroundTask: // iOS Background Fetch - keep it quick (30 second limit) await quickBackgroundRefresh(); break; default: print('Unknown task: $task'); return Future.value(false); // Return false for retry } final duration = DateTime.now().difference(startTime); print('Task completed in ${duration.inSeconds}s'); return Future.value(true); // Success } catch (e, stackTrace) { print('Task failed: $e'); print('Stack trace: $stackTrace'); // Decide whether to retry based on error type if (isRetryableError(e)) { return Future.value(false); // Retry with backoff } else { throw Exception('Permanent failure: $e'); // Don't retry } } }); } bool isRetryableError(dynamic error) { final errorString = error.toString().toLowerCase(); return errorString.contains('network') || errorString.contains('timeout') || errorString.contains('temporary'); } ``` -------------------------------- ### Register One-Off Tasks Source: https://context7.com/fluttercommunity/flutter_workmanager/llms.txt Schedules a task to run once after an optional delay. Supports input data, constraints, and backoff policies. ```dart import 'package:workmanager/workmanager.dart'; // Basic one-off task Workmanager().registerOneOffTask( "sync-task-1", // uniqueName - identifies the task "data_sync", // taskName - passed to callback dispatcher initialDelay: Duration(seconds: 10), ); // One-off task with input data and constraints Workmanager().registerOneOffTask( "upload-task-${DateTime.now().millisecondsSinceEpoch}", "file_upload", inputData: { 'fileName': 'document.pdf', 'uploadUrl': 'https://api.example.com/upload', 'retryCount': 3, 'userId': 12345, }, initialDelay: Duration(minutes: 5), constraints: Constraints( networkType: NetworkType.connected, // Require internet connection requiresBatteryNotLow: true, // Don't run when battery is low requiresCharging: false, // Can run when not charging requiresDeviceIdle: false, // Can run when device is active requiresStorageNotLow: true, // Don't run when storage is low ), existingWorkPolicy: ExistingWorkPolicy.replace, backoffPolicy: BackoffPolicy.exponential, backoffPolicyDelay: Duration(seconds: 30), tag: "uploads", ); ``` -------------------------------- ### Run Dart Analyze Source: https://github.com/fluttercommunity/flutter_workmanager/blob/main/CLAUDE.md Analyze Dart code for errors and potential issues. This is a mandatory pre-commit check. ```bash dart analyze ``` -------------------------------- ### Regenerate Pigeon API files Source: https://github.com/fluttercommunity/flutter_workmanager/blob/main/CONTRIBUTING.md Use this command after modifying the Pigeon API definition in the platform interface package. ```bash # Regenerate Pigeon files melos run generate:pigeon ``` -------------------------------- ### Test Task Logic via UI Source: https://github.com/fluttercommunity/flutter_workmanager/blob/main/docs/debugging.mdx Create a debug button in the UI to trigger and test background task logic manually. ```dart // Add a debug button to test task logic ElevatedButton( onPressed: () async { // Test the same logic that runs in background final result = await performTask('test_task', {'debug': true}); print('Test result: $result'); }, child: Text('Test Task Logic'), ) ``` -------------------------------- ### Implement Custom Debug Handlers Source: https://github.com/fluttercommunity/flutter_workmanager/blob/main/docs/debugging.mdx Create custom handlers to manage task status updates and exceptions on Android and iOS. ```kotlin class CustomDebugHandler : WorkmanagerDebug() { override fun onTaskStatusUpdate(context: Context, taskInfo: TaskDebugInfo, status: TaskStatus, result: TaskResult?) { // Custom status handling logic // See Task Status documentation for detailed status information } override fun onExceptionEncountered(context: Context, taskInfo: TaskDebugInfo?, exception: Throwable) { // Handle exceptions } } WorkmanagerDebug.setCurrent(CustomDebugHandler()) ``` ```swift class CustomDebugHandler: WorkmanagerDebug { override fun onTaskStatusUpdate(taskInfo: TaskDebugInfo, status: TaskStatus, result: TaskResult?) { // Custom status handling logic // See Task Status documentation for detailed status information } override fun onExceptionEncountered(taskInfo: TaskDebugInfo?, exception: Error) { // Handle exceptions } } WorkmanagerDebug.setCurrent(CustomDebugHandler()) ``` -------------------------------- ### Implement iOS Background Task Logging Source: https://github.com/fluttercommunity/flutter_workmanager/blob/main/docs/debugging.mdx Use this callback dispatcher to log task execution status and errors specifically for iOS background tasks. ```dart @pragma('vm:entry-point') void callbackDispatcher() { Workmanager().executeTask((task, inputData) async { print('[iOS BG] Task started: $task at ${DateTime.now()}'); try { // Your task logic final result = await performTask(); print('[iOS BG] Task completed successfully'); return true; } catch (e) { print('[iOS BG] Task failed: $e'); return false; } }); } ``` -------------------------------- ### Generate Pigeon Files Source: https://github.com/fluttercommunity/flutter_workmanager/blob/main/CLAUDE.md Use Melos to regenerate Pigeon interface files. This is part of the code generation process. ```bash melos run generate:pigeon ``` -------------------------------- ### Advanced Task Identification and Routing Source: https://github.com/fluttercommunity/flutter_workmanager/blob/main/docs/customization.mdx Use unique naming conventions and switch logic within the callback dispatcher to handle different task types. ```dart // Good: Specific and unique Workmanager().registerOneOffTask( "user-${userId}-photo-upload-${timestamp}", "upload_task", inputData: {'userId': userId, 'type': 'photo'} ); // Avoid: Generic names that might conflict Workmanager().registerOneOffTask( "task1", "upload", // ... ); ``` ```dart // Use descriptive task type names in your callback @pragma('vm:entry-point') void callbackDispatcher() { Workmanager().executeTask((task, inputData) async { switch (task) { case 'photo_upload': return await handlePhotoUpload(inputData); case 'data_sync': return await handleDataSync(inputData); case 'cache_cleanup': return await handleCacheCleanup(inputData); case 'notification_check': return await handleNotificationCheck(inputData); default: print('Unknown task: $task'); return Future.value(false); } }); } ``` -------------------------------- ### Workmanager.registerOneOffTask Source: https://context7.com/fluttercommunity/flutter_workmanager/llms.txt Schedules a one-time background task that executes once after an optional initial delay. The task can be configured with constraints, backoff policies, and input data. ```APIDOC ## Workmanager.registerOneOffTask ### Description Schedules a one-time background task that executes once after an optional initial delay. The task can be configured with constraints, backoff policies, and input data. ### Method `Workmanager().registerOneOffTask()` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None (parameters are passed directly to the method) - **uniqueName** (String) - Required - A unique identifier for the task. - **taskName** (String) - Required - The name of the task, passed to the callback dispatcher. - **initialDelay** (Duration) - Optional - The delay before the task can start. - **inputData** (Map) - Optional - Data to be passed to the task. - **constraints** (Constraints) - Optional - Conditions that must be met for the task to run. - **networkType** (NetworkType) - Optional - Network requirements (e.g., `NetworkType.connected`, `NetworkType.notRequired`). - **requiresBatteryNotLow** (bool) - Optional - Whether the task requires the battery not to be low. - **requiresCharging** (bool) - Optional - Whether the task requires the device to be charging. - **requiresDeviceIdle** (bool) - Optional - Whether the task requires the device to be idle. - **requiresStorageNotLow** (bool) - Optional - Whether the task requires storage not to be low. - **existingWorkPolicy** (ExistingWorkPolicy) - Optional - Policy for handling existing tasks with the same name (e.g., `ExistingWorkPolicy.replace`). - **backoffPolicy** (BackoffPolicy) - Optional - The backoff policy for retries (e.g., `BackoffPolicy.exponential`). - **backoffPolicyDelay** (Duration) - Optional - The delay for the backoff policy. - **tag** (String) - Optional - A tag to associate with the task. ### Request Example ```dart Workmanager().registerOneOffTask( "sync-task-1", "data_sync", initialDelay: Duration(seconds: 10), ); Workmanager().registerOneOffTask( "upload-task-${DateTime.now().millisecondsSinceEpoch}", "file_upload", inputData: { 'fileName': 'document.pdf', 'uploadUrl': 'https://api.example.com/upload', 'retryCount': 3, 'userId': 12345, }, initialDelay: Duration(minutes: 5), constraints: Constraints( networkType: NetworkType.connected, requiresBatteryNotLow: true, requiresCharging: false, requiresDeviceIdle: false, requiresStorageNotLow: true, ), existingWorkPolicy: ExistingWorkPolicy.replace, backoffPolicy: BackoffPolicy.exponential, backoffPolicyDelay: Duration(seconds: 30), tag: "uploads", ); ``` ### Response No specific response body is detailed for this method, as it primarily schedules tasks. ``` -------------------------------- ### Define Background Task Handler Source: https://github.com/fluttercommunity/flutter_workmanager/blob/main/docs/quickstart.mdx The `callbackDispatcher` must be a top-level function as it runs in a separate isolate. It handles different task types defined by strings. ```dart @pragma('vm:entry-point') void callbackDispatcher() { Workmanager().executeTask((task, inputData) async { switch (task) { case "data_sync": await syncDataWithServer(); break; case "cleanup": await cleanupOldFiles(); break; case Workmanager.iOSBackgroundTask: // iOS Background Fetch task await handleBackgroundFetch(); break; default: // Handle unknown task types break; } return Future.value(true); }); } ``` -------------------------------- ### Print scheduled tasks Source: https://context7.com/fluttercommunity/flutter_workmanager/llms.txt Outputs details of scheduled tasks for debugging. Only available on iOS 13+. ```dart import 'package:workmanager/workmanager.dart'; // Print scheduled tasks for debugging (iOS only) if (Platform.isIOS) { final tasksInfo = await Workmanager().printScheduledTasks(); print('Scheduled tasks:\n$tasksInfo'); // Output example: // [BGTaskScheduler] Task Identifier: com.yourapp.task earliestBeginDate: 2023.10.10 PM 11:10:12 // [BGTaskScheduler] There are no scheduled tasks } ``` -------------------------------- ### Design Efficient Background Tasks Source: https://github.com/fluttercommunity/flutter_workmanager/blob/main/docs/customization.mdx Ensure background tasks are quick and focused to avoid timeouts, especially on iOS where there's a 30-second limit. ```dart // Good: Quick, focused tasks @pragma('vm:entry-point') void callbackDispatcher() { Workmanager().executeTask((task, inputData) async { // Fast operation await syncCriticalData(); return Future.value(true); }); } ``` ```dart // Avoid: Long-running operations @pragma('vm:entry-point') void callbackDispatcher() { Workmanager().executeTask((task, inputData) async { // This might timeout on iOS (30-second limit) await processLargeDataset(); // ❌ Too slow return Future.value(true); }); } ``` -------------------------------- ### Simulate BGTaskScheduler Task in Xcode Source: https://github.com/fluttercommunity/flutter_workmanager/blob/main/docs/debugging.mdx Trigger a specific background task manually from the Xcode console while the app is running. ```objc // Trigger specific BGTaskScheduler task e -l objc -- (void)[[BGTaskScheduler sharedScheduler] _simulateLaunchForTaskWithIdentifier:@"com.yourapp.task.identifier"] ``` -------------------------------- ### Generate Dart Files Source: https://github.com/fluttercommunity/flutter_workmanager/blob/main/CLAUDE.md Use Melos to regenerate Dart files, including mocks. Ensure mocks are up-to-date before running tests in the workmanager package. ```bash melos run generate:dart ``` -------------------------------- ### Monitor Scheduled Tasks on iOS Source: https://github.com/fluttercommunity/flutter_workmanager/blob/main/docs/debugging.mdx Retrieve and print a list of tasks currently scheduled by the system on iOS 13+. ```dart // iOS 13+ only if (Platform.isIOS) { final tasks = await Workmanager().printScheduledTasks(); print('Scheduled tasks: $tasks'); } ``` -------------------------------- ### Define Battery and Device Constraints Source: https://context7.com/fluttercommunity/flutter_workmanager/llms.txt Configure constraints related to battery and device status. 'requiresBatteryNotLow' ensures the task runs only when the battery is not low, and 'requiresCharging' requires the device to be charging. ```dart import 'package:workmanager/workmanager.dart'; // Battery-conscious task final batteryConstraints = Constraints( requiresBatteryNotLow: true, requiresCharging: false, ); ``` -------------------------------- ### Register Periodic Task with Frequency in AppDelegate.swift Source: https://github.com/fluttercommunity/flutter_workmanager/blob/main/docs/quickstart.mdx Register a periodic task identifier in AppDelegate.swift, specifying the desired frequency in seconds. ```swift import workmanager_apple // In application didFinishLaunching WorkmanagerPlugin.registerPeriodicTask( withIdentifier: "com.yourapp.periodic_task", frequency: NSNumber(value: 20 * 60) // 20 minutes (15 min minimum) ) ```