Releases: brewkits/native_workmanager
v1.2.7 - Enforce DartWorker timeoutMs end-to-end (Issue #30)
Fixed
- Core: Enforced
DartWorker.timeoutMsend-to-end (Issue #30).- Android and iOS bridges now correctly forward
timeoutMsto the Dart callback dispatcher. - Added
resolveDispatcherTimeouthelper in Dart to securely parse the timeout, protecting againstNaN,Infinity, and invalid types. - Enforced
timeoutMsin both the background dispatcher and the foregroundMethodChannel(_executeDartCallback). - Added comprehensive unit, integration, performance, and security test coverage.
- Android and iOS bridges now correctly forward
v1.2.6: Industrial Stability & Foreground Service (FGS) Bypass
🚀 Version 1.2.6: Industrial-Grade Background Reliability
This release marks a major milestone in production stability, introducing industrial-grade mechanisms to bypass modern OS background restrictions and eliminating critical concurrency issues.
🌟 Key Highlights
🛡️ Android: Industrial Foreground Service (FGS) Bypass
Run heavy, long-running tasks without being killed by Android 12+ battery optimizations.
- Priority Execution: Promotes tasks to system-level Foreground Services.
- Custom Notifications: Full control over title, body, and action buttons (e.g., 'Stop Sync').
- Android 14 Ready: Automatically handles FGS types and required system permissions.
⚡ Android: Expedited Work (Locked Device Support)
Resolved the regression where tasks wouldn't fire when the screen was locked.
- Doze Mode Bypassing: Maps
allowWhileIdle: trueto WorkManager's Expedited Work. - Instant Triggering: Tasks fire reliably even on idle or locked devices.
💎 iOS: Swift Concurrency & Deadlock Fixes
- Serial Database Queues: Migrated all SQLite stores to serial queues to eliminate deadlocks.
- Scheduling Reliability: Integrated micro-delays for complex
TaskGraphchains to ensureBGTaskSchedulerregistration success.
🛠 Full Change Log
Added
- Android: Industrial-grade Foreground Service support via
ForegroundNotificationConfig. - Android: Proactive task promotion using
setForeground()for immediate background execution. - Android: Full compliance with Android 14 (API 34) Foreground Service Types.
- Example: New 'FGS Bypass' demo page showing real-time priority task execution.
Fixed
- Android: Fixed regression where background tasks would not fire on locked devices (#28).
- iOS: Fixed Swift Concurrency deadlocks affecting
OfflineQueueandTaskGraph. - iOS: Synchronized background task identifiers between Swift code and setup scripts.
- Test: Platform-aware integration test suite with automatic iOS Simulator isolation.
Documentation
- Architecture: Deep-dive into v1.2.6 reliability enhancements in
ARCHITECTURE_ANALYSIS.md. - Concurrency: Defined new serial-queue threading contract in
CONCURRENCY.md. - Migration: Step-by-step guide for using new FGS features.
📦 Installation
Update your pubspec.yaml:
dependencies:
native_workmanager: ^1.2.6Note for Android: To ensure tasks survive app kills, please ensure your Application class implements Configuration.Provider as described in our Android Setup Guide.
v1.2.5
What's changed
Fixed
- Core — Issue #26: Removed over-restrictive
assertinTaskTrigger.periodicthat rejectedinitialDelay + runImmediately: false. Both parameters are independently valid; the OS handles them correctly. Previously threwAssertionErrorat runtime. - iOS:
runImmediatelyflag was being silently recomputed frominitialDelayinKMPSchedulerBridge.swiftinstead of using the caller-provided value. The bridge now passes through the exact value set by the caller.
What initialDelay + runImmediately: false means
await NativeWorkManager.enqueue(
taskId: 'hourly-sync',
trigger: TaskTrigger.periodic(
const Duration(hours: 1),
initialDelay: const Duration(minutes: 30), // first execution starts after 30 min
runImmediately: false, // first period is a full interval
),
worker: NativeWorker.httpSync(url: 'https://api.example.com/sync'),
);Both parameters can be combined freely. The OS decides the exact scheduling within the declared window.
Also in this release
- iOS logging: 148 bare
print()calls across 9 worker files replaced withNativeLogger.d/w/e()— debug output is now gated behindinitialize(debugMode: true)in production builds. - iOS source: Removed internal sprint/T3 planning comments from
HttpDownloadWorker.swiftandHttpUploadWorker.swift. - README: iOS badge corrected to
iOS 14.0+(matches podspec deployment target); install snippet updated to^1.2.5. - Tests: Added
periodic_trigger_reproduction_test.dart— 8-case integration regression suite covering allTaskTrigger.periodicparameter combinations, including the Issue #26 regression. native_workmanager_gen: Version synced to 1.2.5; README install version updated to^1.2.5; CHANGELOG reformatted to Keep-a-Changelog standard.
Migration
No breaking changes. Update your pubspec.yaml:
dependencies:
native_workmanager: ^1.2.5If you use the code generator:
dev_dependencies:
native_workmanager_gen: ^1.2.5Full changelog: CHANGELOG.md
KMP core: kmpworkmanager v2.4.3
v1.2.4
What's Changed
Fixed
- Android: Added automatic ProGuard rules to prevent task classes from being stripped in Release builds (#24).
- Android: Clarified that
Applicationclass setup is required for all tasks to survive app kill. - iOS: Synchronized background task identifiers between
setup_ios.dartand Swift code. - iOS:
getTaskStatus()now correctly returnsTaskStatus.completedfor finished tasks. Previously, the iOS plugin wrote"success"to SQLite but Dart'sTaskStatusenum has nosuccesscase, so every call returnednull. - Android: Removed duplicate
taskStore.updateStatus()call on task completion. The redundant second write usedJSONObject(map).toString()which could corrupt nested result maps. - iOS:
FlutterEngineManagernow disposes the engine after a Dart callback timeout. Previously the engine remained stuck inisInitialized = true, causing all subsequentDartCallbackWorkertasks to silently fail.
Changed
- Engine: Upgraded core
kmpworkmanagerto v2.4.3 on both Android (Maven) and iOS (xcframework).
Tests
- Unit test suite expanded from 898 to 1799 tests.
Upgrading
dependencies:
native_workmanager: ^1.2.4Full Changelog: v1.2.3...v1.2.4
v1.2.3 (Security & Stability Fixes)
[1.2.3] - 2026-04-24
Critical Security & Stability Fixes
- iOS: Fix
URLSessionBackground File Loss: Addressed a critical bug whereBackgroundSessionManagerdispatched file movement asynchronously, causing the OS to delete the downloaded file before the move completed. Implemented a blocking copy before the delegate returns to ensure 100% file retention. - iOS: Fix
BGTaskSchedulerStarvation & Race Condition: Replaced singleton-based completion flag withTaskCompletionGuardtied to the individual BGTask's lifecycle. Replaced peek/remove queue logic withpopNextPendingTask()insidequeue.sync. This prevents multiple tasks stepping on each other and avoids OS penalties due to uncompleted background tasks. - iOS: Fix Missing I/O Interruption on Cancel: The iOS cancellation handler now correctly invokes
worker.stop()(which callsURLSessionTask.cancel()), immediately dropping mid-flight network connections instead of waiting for the next cooperative checkpoint. - Android: Bypass 10KB WorkManager Hard Limit:
WorkManagerthrows an exception if the input data payload exceeds 10KB. The plugin now gracefully handles oversized payloads by spilling them to a secure.jsonfile (wm_spill_*.json) in the cache directory, passing only the file URI toWorkManager, and seamlessly re-hydrating the payload inBaseKmpWorker. - Android: Fix
OfflineQueueProcessorInfinite Loop: Catch-block in the offline queue loop now properly deletes corrupted entries that throw during enqueue (like oversized payloads prior to the spill fix). This prevents the processor from getting stuck in an infinite retry loop that drains the battery. - Security: Advanced Input Validation: All native workers now perform strict validation to block Null Byte Injection, Path Traversal (
..,%2e%2e), and Shell Injection characters in URLs and file paths.
Added
- Feature: Support
initialDelayandrunImmediatelyfor periodic tasks (#21)- Allows delaying the first execution of a periodic task.
- Added
runImmediatelyflag to skip the first execution. - On Android, uses native
PeriodicWorkRequest.setInitialDelay(). - On iOS, maps
initialDelaytoearliestBeginDatefor optimized scheduling. - Added parameters to
TaskTrigger.periodic().
- Enterprise-Grade Testing:
- Implemented comprehensive
scripts/run_all_tests.shcovering Unit, Integration, Security, Performance, and Stress tests. - Added specific performance benchmarks for task scheduling overhead.
- Added malicious payload protection tests.
- Implemented comprehensive
- Improved CI/CD: Integrated automated Security, Performance, and Stress testing into the GitHub Actions pipeline.
Fixed (General)
- Android: Upgraded to
kmpworkmanager 2.4.1- Switched to native
setInitialDelayinstead of manual bypass logic. - Fixed edge-case crashes on Android 15.
- Switched to native
- iOS: Improved Periodic Task Lifecycle
- Fixed regression where periodic tasks were not tracked in
activeTasks, preventing cancellation.
- Fixed regression where periodic tasks were not tracked in
- Android: Fixed broken
expeditedflag logic in direct enqueue path.
v1.2.2: Plugin Registration, iOS Window & Android Middleware Fixes
Added
registerPluginsparameter inNativeWorkManager.initialize(): opt-in flag to register all Flutter plugins in the background engine, required when using plugins likeflutter_local_notificationsinsideDartWorkercallbacks. Defaults tofalseto preserve the Zero-Engine I/O principle and avoid side-effects (e.g. Bluetooth disconnects). Also addedNativeWorkmanagerPlugin.setPluginRegistrantCallbackon Android and iOS to allow selective plugin registration whenregisterPluginsis false. (#18)
Fixed
- iOS:
openFilealways fails on Flutter 3.38+ / scene-based apps —UIApplication.shared.keyWindowreturnsnilinUIWindowScenelifecycle. Replaced with a newactiveRootViewControllerextension that traversesconnectedScenesto find the active key window. (#16) - Android:
StackOverflowErrorwhen middleware is registered — Kotlin companion extensionapplyMiddlewarewas shadowing the internal package-level function of the same name, causing infinite recursion. Renamed the internal function toapplyMiddlewareInternalto eliminate the ambiguity. (#17) native_workmanager_genincompatible with Flutter 3.41.x —analyzer >=11.0.0requiresmeta ^1.18.0which conflicts with the Flutter SDK'smeta 1.17.0pin. Widened constraint to>=10.0.0 <13.0.0;analyzer 10.xsupports all APIs used by the generator and requires onlymeta ^1.15.0. (#15)
v1.2.1 - Security Hardening & Test Suite Enhancements
Security Hardening
- HTTPS Enforcement: Option to block plain HTTP requests.
- SSRF Protection: Option to block private/loopback IP ranges.
- Path Traversal: Enhanced validation against null-byte and encoded dot-segment injection.
Test Suite Enhancements
- 100+ new test cases across unit, security, and integration categories.
- Multi-stage workflow verification (Download -> Encrypt -> Dart Finalizer).
- High-load stress testing (30+ concurrent tasks).
Native Improvements
- Android: Hard isolate timeouts to prevent memory leaks.
- Android: Batch deletion for task store maintenance.
- Observability: New type-safe
WorkManagerLoggerinterface.
Fixed
- Migration Tool: Fixed missing executable for
dart run native_workmanager:migrate(#14).
v1.2.0
What's new in v1.2.0
Added
- Android cold-start
DartWorkerpersistence:DartWorkertasks now execute reliably after app kill. ThecallbackHandleis persisted toSharedPreferences(Android) andUserDefaults(iOS) duringinitialize()and automatically restored when WorkManager restarts the process. Requires host app to implementConfiguration.Provider— see Android Setup Guide. - Advanced Remote Trigger: Support for direct commands in push payloads (
native_wmkey). Execute tasks, chains (enqueue_chain), graphs, and offline queues without waking Flutter. - HMAC Security: HMAC SHA-256 signature verification for remote triggers to prevent unauthorized task execution.
- Real-time Observability: DevTools extension real-time event streaming via
developer.postEvent. - Global Middleware API:
HeaderMiddleware,RemoteConfigMiddleware,LoggingMiddleware. - Task Graphs (DAG): Arbitrary dependency graphs on Android with DFS cycle detection.
- Code Generation:
native_workmanager_gengenerates type-safe callback IDs and worker registries from@WorkerCallbackannotations.
See CHANGELOG for full details.
v1.1.2 — TaskHandler, BLE fix, FakeWorkManager fix
What's New
New: TaskHandler — per-task progress and result
enqueue() now returns a TaskHandler instead of a raw ScheduleResult:
final handler = await NativeWorkManager.enqueue(
taskId: 'download',
worker: NativeWorker.httpDownload(url: url, savePath: '/tmp/video.mp4'),
);
// Stream progress for this task only
handler.progress.listen((p) {
print('${p.progress}% — ${p.networkSpeedHuman} — ETA ${p.timeRemainingHuman}');
});
// Await completion
final result = await handler.result;Or use the built-in widget:
TaskProgressCard(handler: handler, title: 'Downloading video')Fix: BLE disconnect when using DartWorker (issue #6)
The secondary Flutter engine used for DartWorker tasks was created with automaticallyRegisterPlugins = true, which registered all host-app plugins (including Bluetooth plugins) in the background engine. When the engine was destroyed after the task, it called onDetachedFromEngine() on those plugins — closing the shared BluetoothManager connection and dropping active BLE connections.
Fix: The engine is now created with automaticallyRegisterPlugins = false. Only the callback dispatcher needed for DartWorker is registered explicitly. All built-in native workers (HTTP, file, image, crypto, etc.) were already unaffected.
Thanks to @zhujianguo for identifying and reporting the root cause.
Fix: FakeWorkManager.enqueueResultByTaskId stub was broken
FakeWorkManager.enqueue() was hardcoded to return ScheduleResult.accepted after the TaskHandler refactor, ignoring enqueueResult and enqueueResultByTaskId. Fixed — stubs now work correctly for unit tests.
Breaking Changes
enqueue() and enqueueAll() now return TaskHandler / List<TaskHandler> instead of ScheduleResult / List<ScheduleResult>. Access handler.scheduleResult for the old value.
Migration
// Before
final result = await NativeWorkManager.enqueue(...);
if (result == ScheduleResult.accepted) { ... }
// After
final handler = await NativeWorkManager.enqueue(...);
if (handler.scheduleResult == ScheduleResult.accepted) { ... }v1.1.1 Update core & Fix bugs
What's Changed
Added
- Token Refresh on 401:
HttpRequestWorkerandHttpSyncWorkernow support automatic token refresh viaTokenRefreshConfigwhen the server responds with 401 - Response Validation Patterns: configurable response validation for HTTP workers
http_sync_test.dart: integration test suite forHttpSyncWorker
Changed
- XCFramework simulator slice updated to support arm64 + x86_64
- kmpworkmanager engine upgraded to 2.3.9 (fixes
InvalidForegroundServiceTypeExceptionon Android 16 for heavy tasks) - Workers refactored to use the new
WorkerEnvironmentparameter signature from kmpworkmanager 2.3.8+
Fixed
FlutterEngineManager.dispose()now always resetsisInitializedand nulls the engine reference even whenengine.destroy()throws (fixes chain resume and DartWorker constraint tests after memory pressure events)pausemethod correctly routed on Android
Full Changelog: v1.1.0...v1.1.1