Skip to content

feat: v1.1.0 — 25+ native workers, secure chains, DevTools, security hardening#5

Merged
vietnguyentuan2019 merged 11 commits intomainfrom
refactor/enhance
Apr 5, 2026
Merged

feat: v1.1.0 — 25+ native workers, secure chains, DevTools, security hardening#5
vietnguyentuan2019 merged 11 commits intomainfrom
refactor/enhance

Conversation

@vietnguyentuan2019
Copy link
Copy Markdown
Contributor

Summary

  • 25+ production-grade native workers — PDF, WebSocket, Crypto (AES-256-GCM), File System, Media (EXIF-aware), parallel HTTP download/upload
  • Secure task chains — SQLite-backed persistence, per-step retry, parallel steps via .thenAll(), data flow between steps
  • LoggingMiddleware — fire-and-forget HTTP POST telemetry after each task (fully implemented, was stub)
  • registerMiddleware idempotent — upsert semantics; second call replaces, never accumulates
  • DartWorker.timeoutMs — per-task callback timeout now exposed in Dart API
  • Remote trigger support — FCM (Android) / APNs (iOS) data messages trigger native workers without Flutter wake
  • DevTools extension — real-time task inspection, progress monitoring, background engine debugging
  • Smart Engine caching — Flutter Engine kept alive 5 min after DartWorker, near-instant subsequent steps
  • Adaptive memory management — Engine disposed on onTrimMemory / low-memory signal

Security

  • Certificate pinning + HMAC request signing workers
  • SSRF protection (blocks private/loopback IPs)
  • Zip-bomb + zip-slip hardening

Fixes

  • iOS: resumePendingGraphs() restarts interrupted chains on launch
  • iOS: WorkerResult type mismatch in graph tasks resolved
  • iOS: Atomic barrier blocks fix race conditions in OfflineQueue
  • Android: getTasksByTag/getAllTags/getTaskStatus fall back to SQLite correctly
  • Android: All SQLite stores consolidated to single DB (version 6 + migrations)
  • Android: DFS cycle detection prevents StackOverflowError in task graphs
  • Example: All event listeners guard isStarted — eliminates false "Task failed" toasts
  • Example: Photo backup + image process demos use real JPEG download chains

Tests

  • Unit: 724 passed, 0 failed
  • Integration: 63/63 Android, 63/63 iOS

Packages

  • native_workmanager → v1.1.0
  • native_workmanager_gen → v1.0.0 (first release)

Test plan

  • dart analyze lib/ — no issues
  • flutter pub publish --dry-run — clean (only uncommitted files warning)
  • Unit tests 724/724
  • Device integration tests 63/63 Android + 63/63 iOS

Nguyễn Tuấn Việt and others added 11 commits March 25, 2026 17:12
     ### Tier 1 — Critical bugs

     | Task | Description | Status |
     |------|-------------|--------|
     | T1-1 | Auth token sanitization — `TaskStore.sanitizeConfig()` strips `authToken`, `cookies`, `password`, `secret` before SQLite persist. Both Android (`TaskStore.kt`) and iOS (`TaskStore.swift`) | ✅ Done |
     | T1-2 | Main thread SQLite I/O — `handleAllTasks` on iOS and Android now dispatches to background queue/IO scope | ✅ Done |
     | T1-3 | iOS `handleCancelAll` missing `taskNotifTitles.removeAll()` and `taskAllowPause.removeAll()` | ✅ Done |
     | T1-4 | Android chain persistence — new `ChainStore.kt` (SQLite) + `resumePendingChains()` called on engine attach | ✅ Done |

     ### Tier 2 — Improvements

     | Task | Description | Status |
     |------|-------------|--------|
     | T2-1 | Task store TTL — `cleanupAfterDays` param in `initialize()` → `TaskStore.deleteCompleted(olderThanMs:)` | ✅ Done |
     | T2-2 | HTTPS enforcement — `enforceHttps: bool` param in `initialize()` → `SecurityValidator.enforceHttps` flag | ✅ Done |
     | T2-3 | Custom worker className validation at Dart layer (regex + max length 256 chars) | ✅ Done |
     | T2-4 | Builder pattern for `HttpDownloadWorker` — `copyWith()` + `withNotification()` / `withAuth()` / `withResume()` / `withChecksum()` convenience methods | ✅ Done |
     | T2-5 | `sealed class Worker` (Dart 3.0 exhaustive pattern matching) replacing `abstract base class` | ✅ Done |

     ### Tier 3 — Advanced / New Features

     | Task | Description | Status |
     |------|-------------|--------|
     | T3-1 | iOS Actor-based task state — `TaskActor.swift` created as drop-in replacement for `DispatchQueue + [String: Task]`. **NOT yet integrated into NativeWorkmanagerPlugin.swift** (deliberately deferred as too large a refactor; file is ready as
     `utils/TaskActor.swift`) | ✅ Ready |
     | T3-2 | `parallelHttpUpload` worker — Mirror of `parallelHttpDownload` but for uploads. Each file uploaded as a separate concurrent request with per-host concurrency limit (`HostConcurrencyManager`), retry-per-file, rich progress. All three layers
     complete. | ✅ Done |
     | T3-3 | DartWorker progress reporting — `NativeWorkManager.reportDartWorkerProgress(taskId, progress, message)` from background Dart isolate → `MethodChannel('dev.brewkits/dart_worker_channel')` → `FlutterEngineManager` (both platforms) →
     `ProgressReporter` → Flutter EventChannel | ✅ Done |
     | T3-4 | `ioScope` separation in Android plugin — `CoroutineScope(Dispatchers.IO + SupervisorJob())` for all SQLite and heavy I/O; main `scope` for WorkManager callbacks | ✅ Done |

     ---
…2.3.7

Worker Registry (T3-5):
- Android: per-worker ConcurrentHashMap registry in SimpleAndroidWorkerFactory
  alongside legacy setUserFactory (backward compat preserved)

Bandwidth throttling (T3-6):
- Android: BandwidthThrottle wraps OkHttp ResponseBody via token-bucket
- iOS: BandwidthThrottle actor streams via URLSession.bytes (iOS 15+),
  graceful no-op on iOS 14
- Dart: bandwidthLimitBytesPerSecond field added to HttpDownloadWorker

Request signing HMAC-SHA256 (T3-7):
- Android: RequestSigner applied in HttpDownload/Upload/Request/Sync workers
- iOS: RequestSigner applied in all four HTTP workers
- Dart: RequestSigning config added to all four HTTP worker classes

Troubleshooting guide (T2-6):
- doc/TROUBLESHOOTING.md with iOS/Android chain differences table,
  setup, background execution, custom workers, debugging tips

Chain tests (T2-7):
- Integration tests: cancel-after-first-step + resume-remaining-steps

Build fixes for kmpworkmanager 2.3.7:
- WorkerResult.Success.data changed from Map to JsonObject:
  migrate all 25+ worker sites to buildJsonObject { put(...) }
- Add kotlinx-serialization-json dependency to android/build.gradle
- TaskTrigger.BatteryOkay/BatteryLow/DeviceIdle/StorageLow removed;
  mapped to TaskTrigger.OneTime() with constraints
- Add ScheduleResult.DEADLINE_ALREADY_PASSED branch to when expression
- Add @OptIn(AndroidOnly::class) for TaskTrigger.ContentUri
- Add missing withContext + OkHttpClient imports to NativeWorkmanagerPlugin
- Fix return@downloadBlock → return@withContext for early-return sites
  before the downloadBlock label definition
- Fix existingBytes == 0 → 0L (Long/Int type mismatch)
- Fix okio.buffer(tracked) → tracked.buffer() (Okio 3.x API)
- Fix destinationFile used before declaration in ParallelHttpDownloadWorker
- Fix sealed class Worker → abstract class Worker (cross-file subclassing)
- Fix UploadFile duplicate export conflict in workers.dart
Full analysis of native_workmanager covering:
- Architecture deep-dive (3-layer, KMP engine, design patterns)
- Feature evaluation from PO / BA / Senior Dev perspectives
- Pros/cons matrix with severity ratings
- Competitor comparison (workmanager, flutter_background_service, background_fetch)
- Development roadmap (Phase 1–3, P0/P1/P2 features)
- Feasibility assessment and market positioning
- KPI targets and enterprise adoption strategy
- Technical metrics (codebase size, benchmarks, test coverage)
…1..L-4)

Critical:
- C-1: ParallelHttpDownloadWorker now parses & applies certificatePinning,
  tokenRefresh, requestSigning on Android and iOS (including 401 retry with
  token refresh in each chunk download and sequential fallback)
- C-2: confirmed showNotification/notificationTitle/notificationBody handled
  at plugin layer for all worker types (no ghost issue)

High:
- H-1: AppContextHolder.appContext annotated @volatile for JVM visibility
- H-2: BGTaskSchedulerManager Task closures use [weak self] to prevent
  strong-reference cycle on expirationHandler and executeWorker closures
- H-3: PdfWorker.kt — SecurityValidator.validateFilePathSafe() called for
  all inputPaths, outputPath, imagePaths before File() construction
- H-3 (iOS): PdfWorker.swift — SecurityValidator.validateFilePath() called
  before every URL(fileURLWithPath:) construction
- H-4: Both SecurityValidators now block fe80::/10 IPv6 link-local
  (was only blocking ::1 loopback and fc00::/7 ULA)
- H-5: HttpDownloadWorker and ParallelHttpDownloadWorker use
  Files.move(ATOMIC_MOVE) + AtomicMoveNotSupportedException fallback
  instead of non-atomic File.renameTo()

Medium:
- M-1: ParallelHttpDownloadWorker.kt validates checksumAlgorithm against
  allowlist before MessageDigest.getInstance(); returns shouldRetry=false
  for unsupported algorithm (not a transient error)
- M-2: WebSocketWorker replaces awaitTermination(2s) on shared OkHttp
  dispatcher (always times out) with coroutine delay(250ms)
- M-3: OfflineRetryPolicy._pow() replaced by math.pow(); delayFor() guards
  against infinite result with maxDelay fallback; maxRetries capped at 100
- M-4: HttpUploadWorker.swift boundary changed from static let to instance
  let so each upload uses a unique UUID boundary

Low:
- L-1: OfflineRetryPolicy assert updated; NaN caught by >= 1.0 check;
  Infinity clamped in delayFor via isFinite guard
- L-2: confirmed false positive — iOS calculateChecksum already switches
  on algorithm string for MD5/SHA-1/SHA-256/SHA-512
- L-3: PdfWorker.swift SecurityValidator.validateFilePath() guards added
- L-4: OfflineQueue.cancel() removes from _pending list before firing
  native cancels, eliminating scheduling race window

All 1622 Dart unit tests pass.
…tability fixes

- Add Flutter DevTools extension for real-time background task monitoring.
- Fix iOS SIGKILL by implementing task expiration stop() protocol.
- Fix Android 14 ForegroundServiceStartNotAllowedException via permission handling.
- Restore missing HttpSecurityHelper and TaskEventBus native components.
- Hardened ZipSlip and Path Traversal protections in native workers.
- Fix various Kotlin compilation errors and resource leaks.
- Standardized project versioning to v1.2.0 across all files.
…errors

- Re-create HttpSecurityHelper.swift with CertificatePinningConfig and makeURLSession.
- Move TokenRefreshConfig and AuthTokenManager to HttpSecurityHelper for better organization.
- Fix 'Cannot find CertificatePinningConfig/makeURLSession in scope' errors in ParallelHttpDownloadWorker and HttpUploadWorker.
… KMPBridge

- Move TokenRefreshConfig and AuthTokenManager back to KMPBridge.swift to ensure visibility in existing Xcode project.
- Keep CertificatePinningConfig and makeURLSession in HttpSecurityHelper.swift.
- This fixes compilation errors when newly created files are not automatically picked up by Xcode.
Core additions:
- 25+ production-grade native workers (PDF, WebSocket, Crypto, File, Media)
- Secure task chains with SQLite persistence and per-step retry
- DartWorker.timeoutMs exposed in Dart API
- LoggingMiddleware: HTTP POST telemetry after each task
- registerMiddleware is now idempotent (upsert semantics)
- Remote trigger support (FCM/APNs) without waking Flutter
- DevTools extension for real-time task inspection
- Smart Flutter Engine caching (5-min TTL after DartWorker)
- Adaptive engine disposal on memory pressure

Security:
- AES-256-GCM encryption/decryption workers
- Certificate pinning and HMAC request signing
- SSRF protection blocking private/loopback IPs
- Zip-bomb and zip-slip hardening

Android fixes:
- getTasksByTag/getAllTags/getTaskStatus now fall back to SQLite
- SQLite stores consolidated to single DB with proper migrations
- MiddlewareStore singleton prevents redundant DB connections
- DFS cycle detection prevents StackOverflowError in task graphs

iOS fixes:
- resumePendingGraphs() restarts interrupted graphs on launch
- executeWorkerStateless uses IosWorkerFactory for all worker types
- Race conditions in OfflineQueue fixed with atomic barrier blocks
- WorkerResult type mismatch in graph tasks resolved

Example app:
- All event listeners guard isStarted to prevent false "Task failed" toast
- Photo backup and image process demos use real JPEG download chains
- RenderFlex overflow fixed on small screens

Tests:
- Unit tests: 724 passed
- Integration tests: 63/63 Android, 63/63 iOS

README:
- Redesigned logo (hexagon, clean at small sizes)
- Quick Start moved to top; platform support table added
- Workers reorganised into categorised table
- Real-world use-case examples added (photo backup, encrypt+upload, periodic sync)
@vietnguyentuan2019 vietnguyentuan2019 merged commit 6d50ba5 into main Apr 5, 2026
4 of 10 checks passed
@vietnguyentuan2019 vietnguyentuan2019 deleted the refactor/enhance branch April 5, 2026 06:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant