Skip to content

Releases: brewkits/native_workmanager

v1.4.3 — iOS SwiftPM: manifest fix for stricter toolchains

Choose a tag to compare

@vietnguyentuan2019 vietnguyentuan2019 released this 17 Jul 06:03
5b51256

Fixed

  • iOS SwiftPM: manifest rejected by stricter SwiftPM toolchains. Package.swift declared a test target with path: "../Tests", which escapes the package root. Newer SwiftPM (Xcode 26.x) tolerates it, but stricter toolchains reject the entire manifest at load time ("target 'NativeWorkManagerTests' in package 'native_workmanager' is outside the package root") — breaking dependency resolution for every SPM-enabled consumer on those toolchains, the same failure mode as #49/#52. The test target is removed from the consumer-facing manifest; nothing ever executed it, so no coverage is lost. Root cause confirmed by controlled experiment: the CI job reproducing the failure goes green with the target removed.

With this, all four layers of the SwiftPM install path are verified automatically on every PR: remote binary target resolution, hyphenated product-name resolution, a full flutter build of a consuming app with SwiftPM enabled, and compile under SPM's strict module isolation.

CI

  • Validate PR job: PR title/body now flow through env instead of being inlined into bash — fixes script breakage on special characters and closes a script-injection vector for fork PRs.

No Android or Dart-API changes. The bundled KMPWorkManager.xcframework is unchanged (same v1.4.0 release asset and checksum).

v1.4.2 — iOS SwiftPM: hyphenated library product (issue #52)

Choose a tag to compare

@vietnguyentuan2019 vietnguyentuan2019 released this 17 Jul 04:20
dd3f2bd

Fixed

  • iOS SwiftPM resolution failed one layer above the 1.4.1 fix — Issue #52. Flutter's generated FlutterGeneratedPluginSwiftPackage references every plugin by the hyphenated library product name (SwiftPM uses the product name as CFBundleIdentifier when linking dynamically, and bundle identifiers cannot contain underscores). Package.swift exported the product as native_workmanager, so SPM-enabled apps failed dependency resolution with "product 'native-workmanager' … not found in package 'native_workmanager'". The library product is now native-workmanager; package and target names keep underscores. Thanks @zaqwery for the precise diagnosis — again.
  • iOS: two workers did not compile under SwiftPM. CryptoWorker and FileSystemWorker use UIApplication without an explicit import UIKit; CocoaPods builds compiled anyway via transitive module re-export, SwiftPM builds do not. Explicit imports added.

Changed

  • Release verification now includes a real SwiftPM app build (scratch Flutter app with --enable-swift-package-manager depending on the plugin), exercising Flutter's generated manifest end-to-end. Verified through to a runtime smoke test: native FileSystemWorker executes under an SPM-built app.

No Android or Dart-API changes. The bundled KMPWorkManager.xcframework is unchanged — SwiftPM/CocoaPods installs keep fetching the existing v1.4.0 release asset (same checksum).

v1.4.1 — SwiftPM fix (#49) + Android 15/16 DNS + cancellation handling

Choose a tag to compare

@vietnguyentuan2019 vietnguyentuan2019 released this 16 Jul 13:55
5df3da0

Fixed

  • iOS Swift Package Manager builds failed for pub.dev consumers — Issue #49.
    Package.swift declared KMPWorkManager as a local .binaryTarget
    (path: "../Frameworks/KMPWorkManager.xcframework"), but that xcframework is
    stripped from the published package by .pubignore and only re-created by the
    CocoaPods prepare_command at install time. SwiftPM has no equivalent install
    hook, so with Flutter's SwiftPM integration enabled the local binary target
    resolved to nothing and xcodebuild aborted with "local binary target
    'KMPWorkManager' … does not contain a binary artifact"
    — and because Flutter
    routes a plugin through SwiftPM whenever a Package.swift exists (excluding it
    from CocoaPods), there was no fallback. Replaced the local target with a
    remote, checksummed .binaryTarget pointing at the same GitHub-release zip
    the podspec already downloads, so SwiftPM fetches the identical versioned
    artifact CocoaPods does. Verified end-to-end: SwiftPM downloads the asset,
    validates the checksum, and builds. Thanks @zaqwery for the precise root-cause
    report.

  • CancellationException swallowed by generic exception handling in 11 Android
    workers.
    A worker cancelled mid-run (user calls cancel()/cancelAll(), or
    WorkManager stops the worker because constraints are no longer met) could have
    its CancellationException caught by the worker's own catch (e: Exception)
    and converted into a normal WorkerResult.Failure — in HttpDownloadWorker's
    case with shouldRetry: true, meaning a task the user explicitly cancelled
    could reschedule itself. ForegroundNativeWorker was the most exposed case: it
    bypasses BaseKmpWorker, so nothing else catches cancellation correctly for
    the FGS-bypass path. Fixed by adding catch (e: CancellationException) { throw e } before the generic catch in every worker where the wrapped scope contains
    a real suspension point (network I/O awaited via child coroutines, delay(),
    setForeground()). Affected: DbCleanupWorker, FileCompressionWorker,
    FileDecompressionWorker, FileSystemWorker, ForegroundNativeWorker (two
    sites), HttpDownloadWorker, HttpRequestWorker, HttpSyncWorker,
    HttpUploadWorker, ImageProcessWorker, ParallelHttpDownloadWorker (two
    sites). Five workers audited and confirmed already safe without changes
    (CryptoWorker, MoveToSharedStorageWorker, ParallelHttpUploadWorker,
    PdfWorker rely on BaseKmpWorker's outer CancellationException handling
    since they have no local catch around their dispatch; WebSocketWorker
    already used try/finally instead of try/catch around its
    cancellation-sensitive section).

  • Intermittent "Failed host lookup" on Android 15/16. Bumped
    androidx.work:work-runtime-ktx 2.10.1 → 2.11.2, which fixes an upstream
    AndroidX WorkManager bug where a background WorkRequest could start
    running before the device's network/connectivity state was fully attached,
    causing spurious SocketException: Failed host lookup failures on HTTP
    calls made from background tasks. Found by auditing flutter_workmanager's
    issue tracker (still pinned to 2.10.2 at the time of writing, with an open
    unresolved report) — see issuetracker.google.com/issues/445324855.
    kmpworkmanager pulls in work-runtime-ktx 2.9.1 transitively; the direct
    api declaration here wins Gradle's highest-version resolution (verified:
    ./gradlew :native_workmanager:dependencies resolves 2.9.1 -> 2.11.2).


v1.4.0 — DartWorker retry-on-false + Constraints.maxRetries enforcement

Choose a tag to compare

@vietnguyentuan2019 vietnguyentuan2019 released this 16 Jul 07:56
18f9c99

Changed

  • Bumped kmpworkmanager core to 3.1.0 (was 3.0.1). 3.1.0 enforces Constraints.maxRetries inside BaseKmpWorker: it reads the maxRetries key off the WorkRequest input data and caps Failure(shouldRetry=true) / Retry at N + 1 total runs (WorkManager itself has no max-retry API — a raw Result.retry() reschedules forever). The bundled iOS KMPWorkManager.xcframework was rebuilt from 3.1.0 (attached below — the podspec downloads it for pub.dev installs).

Fixed

  • DartWorker return false never retried — permanent Result.failure(). Android DartCallbackWorker and iOS Dart callback paths mapped a false callback result to WorkerResult.Failure / .failure without shouldRetry: true, so Constraints.maxRetries / backoffDelayMs were ignored despite docs promising retry-on-false. Native engine/setup exceptions still use shouldRetry = false so broken engine configuration does not loop forever. Thanks @rajabilal555 for finding and fixing this (#46).

  • Android Constraints.maxRetries was silently ignored. Even once a task asked to retry, WorkManager's Result.retry() is unbounded, so a callback that kept returning false looped forever. maxRetries is now forwarded onto the KMP Constraints and stamped onto WorkRequest input data for every direct-enqueue path (one-time, chain, graph). Periodic work is intentionally excluded — its runAttemptCount only resets on success. ForegroundNativeWorker enforces the same cap inline. iOS RetryConfig now reads maxRetries via NSNumber (MethodChannel integers were silently dropped to 0 = no retry) and defaults to 3 to match the Dart contract.

Note: this is a behavior change — a DartWorker callback returning false (or throwing) now retries under maxRetries/backoff instead of failing permanently. Set Constraints(maxRetries: 0) for the old fail-fast behavior.

v1.3.3 — DartWorker progress (#38) & persisted status (#39) + HMAC hardening

Choose a tag to compare

@vietnguyentuan2019 vietnguyentuan2019 released this 14 Jul 01:51
9d3f50e

Device-verified on a real Pixel 6 Pro and an iPhone 17 simulator. Both native_workmanager and native_workmanager_gen score 160/160 on pana.

Fixed

  • DartWorker progress events dropped (UI stuck at 0%) — #38. Native emitted the progress map without a timestamp, so the Dart session-filter silently discarded every event. Android ProgressUpdate.toMap()/toJson() and iOS ProgressReporter/emitProgress now stamp timestamp; the Dart filter treats a missing/0 timestamp as "current".
    • Two further iOS-only gaps surfaced by device testing (not covered by the original community fix): __taskId is now injected into a foreground DartWorker's input (executeDartWorkerViaMethodChannel, mirroring Android), and the main Flutter engine now registers the dev.brewkits/dart_worker_channel reportProgress handler so foreground callbacks no longer throw MissingPluginException. reportDartWorkerProgress now works from a foreground DartWorker on both platforms.
  • DartWorker TaskStore status stuck on pending after success — #39. The observeWorkCompletion WorkInfo fallback now persists terminal status to SQLite (running/completed/failed/cancelled), plus a syncTaskStoreWithWorkManager() reconciliation on restart repairs rows left stale by process death. allTasks() now reflects the real lifecycle.

Security

  • Constant-time HMAC signature comparison in RemoteTrigger. Verification compared signatures with plain string equality (Android String.equals, iOS ==), which short-circuits and can leak — via response timing — how many leading bytes matched. Both platforms now compare the raw HMAC bytes in constant time (Android MessageDigest.isEqual, iOS CryptoKit HMAC.isValidAuthenticationCode). Behavior-preserving.

Docs

  • README: replaced the outdated "your Application must implement Configuration.Provider" note with the v1.3.0+ zero-config auto-init story; added a reportDartWorkerProgress example. Install snippets and API reference bumped to 1.3.3.

Companion package

  • native_workmanager_gen synced to 1.3.3 (no codegen changes).

Full changelog: https://github.com/brewkits/native_workmanager/blob/main/CHANGELOG.md

Thanks @rajabilal555 for the #38/#39 root-cause analysis and the original fix (#40).

v1.3.2 — Issue #36 iOS UIScene crash fix + pre-publish hardening

Choose a tag to compare

@vietnguyentuan2019 vietnguyentuan2019 released this 08 Jul 02:27
a85d85e

Fixed

iOS: startup crash on Flutter 3.38+ (UIScene template) — Issue #36

Apps created with the Flutter 3.38+ iOS template register plugins in AppDelegate.didInitializeImplicitFlutterEngine, which runs after application(_:didFinishLaunchingWithOptions:) returns. Calling BGTaskScheduler.register at that point violates Apple's "all launch handlers must be registered before application finishes launching" rule and threw NSInternalInconsistencyException at startup — reported on iPhone 15 / iOS 18.6.2, but affects any device on the new template.

  • BGTask launch handlers now register in an ObjC +load hook (NWMBGTaskRegistrar) that runs at binary load time — always inside the launch window, on both the old and the new template. Plugin registration only attaches the Swift handlers afterwards. No app-side changes required.
  • All BGTaskScheduler.register calls now go through ObjC @try/@catch (Swift cannot catch NSException): late or duplicate registration degrades to a BGTASK_REGISTRATION_FAILED system error instead of a crash.
  • Fixed a latent duplicate-registration crash: registerHandlers() had no idempotency guard, so GeneratedPluginRegistrant re-running on the headless background engine (FlutterEngineManager) re-registered the identifiers and threw the same exception.
  • BGTasks that fire before the Swift side attaches (cold-start background launch) are now buffered and delivered once handlers attach.
  • Fixed along the way: an ObjC bool-boxing bug (@(a != nil) boxes as NSNumber int, which the Flutter standard codec decodes as Dart int rather than bool) in the registrar's debug snapshot — caught by the new issue_36 device integration test.

The example app has been migrated to the Flutter 3.38+ UIScene template (FlutterImplicitEngineDelegate + SceneDelegate) so the device integration suite runs on the exact lifecycle that crashed — that migration is the regression coverage for this fix.

Dependency: kmpworkmanager core 2.5.1 → 3.0.1

Fixes a critical crash on Android 8–11 (API 26–30): expedited tasks threw IllegalStateException: Not implemented due to a missing getForegroundInfo() override, regressed since core v2.3.8. (v3.0.0 also extracted Ktor HTTP workers into the optional kmpworkmanager-http artifact — not used by this plugin, no bridge API changes.)

Added

  • iOS: NativeWorkmanagerPlugin.registerBGTaskHandlers() — optional explicit registration from didFinishLaunchingWithOptions (idempotent, exception-safe). Only needed if a build setup strips ObjC +load sections.
  • native_workmanager_gen: first test suite (previously zero tests despite declaring test: as a dependency) — 15 tests covering code generation, snake_case/kebab-case → camelCase ID conversion, typed-input enqueue wrapper generation, and all 7 validation-error paths.

Documentation

A full pre-publish audit found compile-breaking errors in every documentation file that referenced the public API. All fixed:

  • Nonexistent worker methods documented: imageResize/imageCrop/imageConvert/imageThumbnail (the real API is the unified imageProcess()), parallelDownload (real: parallelHttpDownload), imagesToPdf (real: pdfFromImages), cryptoHash/hmacSign (no such methods exist).
  • Wrong parameter names: maxAttemptsmaxRetries, deviceIdlerequiresDeviceIdle, requiresWifirequiresUnmeteredNetwork, TaskEvent.outputDataresultData.
  • Fabricated APIs that don't exist anywhere in the package: a retryPolicy/RetryPolicy enqueue parameter (retry config actually lives in Constraints(backoffPolicy:, backoffDelayMs:, maxRetries:)), NativeWorkManager.registerCallback() (callbacks register via the dartWorkers map passed to initialize()), a TaskState enum with event.state/.progress/.attemptCount/.error (real TaskEvent fields are success, isStarted, message, errorCode, resultData), ImageCropRect (real type is dart:ui's Rect), and an enqueueToQueue() method (offline queueing goes through OfflineQueue/QueueEntry/OfflineRetryPolicy).
  • Every @pragma('vm:entry-point') callback sample across the Dio, Firebase, Sentry, and Hive integration guides used the wrong signature (Future<void> fn(String? input)) instead of the real DartWorkerCallback signature (Future<bool> Function(Map<String, dynamic>? input)) — roughly 35 functions corrected.
  • ForegroundServiceType enum reference listed 7 values that don't exist and omitted the 2 real ones.
  • Stale version pins (v1.0.x–v1.2.x) across README and all guides updated to v1.3.2.

Every fix was verified against the actual lib/src/*.dart source — not guesswork.

Cleanup

  • Removed 4 leftover debug print() calls from TaskGraph's internal executor.
  • Removed 8 dead/orphaned scratch files from the example app (one-off issue-verification scripts, an unwired demo entry point, unused duplicate widgets) — none were referenced anywhere in the app.
  • Fixed the demo app displaying a hardcoded "v1.2.7" in its UI (title bar, engine log, app bar) despite shipping v1.3.2.

Verification

  • flutter analyze: 0 issues (both native_workmanager and native_workmanager_gen)
  • Host test suite: 1883/1883 passing (unit, security, performance, integration, workers, widgets)
  • native_workmanager_gen test suite: 15/15 passing (new)
  • Device integration tests on real hardware across 8 groups — All Workers, Constraints, Task Chains, Events, Cancellation, Trigger Types, Custom Native Workers, and the new issue_36 group — all green on both platforms
  • Demo app built, installed, and driven manually on both platforms with log capture

Notes

  • native_workmanager_gen companion package bumped to 1.3.2 (in sync).
  • No Flutter SDK version bump required — the fix is template-agnostic; the pubspec.yaml constraint stays >=3.27.0.

Full Changelog: v1.3.1...v1.3.2

v1.3.1

Choose a tag to compare

@vietnguyentuan2019 vietnguyentuan2019 released this 07 Jun 16:44
659b38d

Fixed

Android (critical regression, since v1.2.4)

All file-based native workers (HttpDownload, HttpUpload, ParallelHttpDownload/Upload, FileCompression, FileDecompression, ImageProcess, Crypto hash/encrypt/decrypt, Pdf, WebSocket, FileSystem, MoveToSharedStorage) failed on real devices with Invalid or unsafe file path. v1.2.4 added a blanket "/data" entry to SecurityValidator's blocked-prefix list, which rejected the app's own private sandbox (/data/data/<pkg>, /data/user/<n>/<pkg> — exactly what path_provider returns). The validator now blocks only the genuinely OS-owned sub-directories of /data while allowing the app sandbox. Path-traversal protection and blocking of /proc, /sys, /etc, /system, /vendor, /dev, /root are unchanged.

Verified on Pixel 6 Pro (Android 16): the "All Workers" integration group passes 15/15.

iOS (#33)

KMPWorkManager.xcframework was extracted into a double-nested path (Frameworks/Frameworks/KMPWorkManager.xcframework) during pod install, causing iOS builds to fail with Unable to find module dependency: 'KMPWorkManager'. The prepare_command in native_workmanager.podspec is now layout-agnostic.

Notes

  • The framework binary (kmpworkmanager 2.5.1) is unchanged; the podspec continues to download the xcframework from the v1.3.0 release asset.
  • native_workmanager_gen companion package also bumped to 1.3.1.

Full Changelog: v1.3.0...v1.3.1

v1.3.0 - Zero-Config Auto-Init & Unified CLI

Choose a tag to compare

@vietnguyentuan2019 vietnguyentuan2019 released this 04 Jun 05:37
942dbc0

[1.3.0] - 2026-06-04

Added

  • Android Auto-Init (NativeWorkManagerInitializer): Plugin now ships an androidx.startup
    Initializer declared in its own AndroidManifest.xml. It runs automatically before
    Application.onCreate(), restoring the callbackHandle from SharedPreferences and
    initializing KmpWorkManager with SimpleAndroidWorkerFactory.

    • Breaking zero-config change: DartWorker killed-app support now requires no custom
      Application class and no manual AndroidManifest.xml edits
      for the common case.
    • Opt-out for apps with custom WorkManager configuration: add
      <meta-data android:name="native_workmanager.auto_init" android:value="false" /> to
      <application> in your AndroidManifest.xml, then follow doc/ANDROID_SETUP.md.
    • isSchedulerInitialized flag prevents double-initialization when onAttachedToEngine
      runs after the Initializer.
  • Unified setup CLI (dart run native_workmanager:setup): Evolves setup_ios into a
    universal command covering both platforms.

    • --android: validates the app manifest has no conflicts with auto-init.
    • --ios: patches Info.plist with UIBackgroundModes and
      BGTaskSchedulerPermittedIdentifiers (same as the legacy setup_ios command).
    • --check: read-only validation mode — no files are written.
    • --help: full usage reference.
    • setup_ios executable retained for backward compatibility.
  • iOS WorkerResult.retry(): Added retry(reason:delayMs:attemptCap:) factory on
    the Swift WorkerResult struct, providing parity with WorkerResult.Retry introduced
    in kmpworkmanager v2.5.0.

Changed

  • Core: Upgraded KMP WorkManager core dependency from v2.4.3 to v2.5.1.

    • Android: added WorkerResult.Retry branch in ForegroundNativeWorker to satisfy
      sealed-class exhaustiveness (maps to Result.retry()).
    • iOS KMPWorkManager.xcframework rebuilt from v2.5.1 source.
  • iOS retry semantics (executeWorkerSync): the retry loop now respects
    WorkerResult.shouldRetry. A worker returning failure(shouldRetry: false) stops
    retrying immediately instead of exhausting all maxRetries attempts.

  • iOS maxRetries honored on the direct-task execution path: RetryConfig.from(constraintsMap:)
    is now called and passed to executeWorkerSync. Previously Constraints.maxRetries was
    silently ignored on iOS (dead code).

  • iOS direct-task qos now read from constraintsMap["qos"] instead of being
    hardcoded to "background".

Fixed

  • Android DartCallbackWorker: CancellationException is now rethrown before the
    outer catch (Exception) block. executeDartCallback is a suspending function; without
    this fix, WorkManager task cancellation was silently converted to a Failure result.

  • iOS WebSocket: NativeWorker.webSocket() now throws UnsupportedError at call-site
    when run on iOS. Previously the task was enqueued and silently failed with
    "Unknown worker class" because IosWorkerFactory has no WebSocketWorker case.

  • Android handleResume: constraint JSON parse failure now logs a NativeLogger.w
    warning instead of silently falling back to empty constraints (which could cause resumed
    downloads to ignore requiresNetwork / requiresCharging).

  • Dart resolveDispatcherTimeout: values ≤ 0 (zero, negative, NaN, ±Infinity) now
    fall back to the 25 s default. A Duration(milliseconds: -n).timeout() fires immediately,
    which would kill every DartWorker. Added four regression tests.

  • Android HttpDownloadWorker — data corruption (directory mode): concurrent downloads
    to the same directory now each use their own temp file (__pending_<taskId>__.tmp)
    instead of sharing the hardcoded __pending__.tmp. Two workers writing to the same
    temp path produced a mixed-byte file; the first to finish would rename corrupted data.

  • Android HttpDownloadWorker — TOCTOU rename (onDuplicate: "rename"): replaced
    findNextAvailableFile() + Files.move(REPLACE_EXISTING) with an atomic probe loop using
    ATOMIC_MOVE only (no REPLACE_EXISTING). A FileAlreadyExistsException now signals
    the next candidate rather than silently overwriting a file from a concurrent download.

  • Android constraint conflict warning: enqueueing with allowWhileIdle: true and
    isHeavyTask: true simultaneously now logs a NativeLogger.w at enqueue time. The
    long-running worker already bypasses Doze mode, making allowWhileIdle redundant and
    potentially causing WorkManager rejection on some Android versions.

v1.2.7 - Enforce DartWorker timeoutMs end-to-end (Issue #30)

Choose a tag to compare

@vietnguyentuan2019 vietnguyentuan2019 released this 11 May 16:20
866ca89

Fixed

  • Core: Enforced DartWorker.timeoutMs end-to-end (Issue #30).
    • Android and iOS bridges now correctly forward timeoutMs to the Dart callback dispatcher.
    • Added resolveDispatcherTimeout helper in Dart to securely parse the timeout, protecting against NaN, Infinity, and invalid types.
    • Enforced timeoutMs in both the background dispatcher and the foreground MethodChannel (_executeDartCallback).
    • Added comprehensive unit, integration, performance, and security test coverage.

v1.2.6: Industrial Stability & Foreground Service (FGS) Bypass

Choose a tag to compare

@vietnguyentuan2019 vietnguyentuan2019 released this 09 May 03:52

🚀 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: true to 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 TaskGraph chains to ensure BGTaskScheduler registration 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 OfflineQueue and TaskGraph.
  • 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.6

Note for Android: To ensure tasks survive app kills, please ensure your Application class implements Configuration.Provider as described in our Android Setup Guide.