https://github.com/brewkits/native_workmanager
Native WorkManager: High-performance Flutter background Task Chains with zero-overhead. Harness the full power of Android WorkManager & iOS BGTaskScheduler using pure Kotlin/Swift Workers.
https://github.com/brewkits/native_workmanager
android-workmanager background background-fetch background-processing background-tasks battery-efficient flutter flutter-plugin headless-execution ios-background-tasks kmp kotlin kotlin-multiplatform memory-optimization native-performance performance-tuning swift task-chaining task-scheduler workmanager
Last synced: 13 days ago
JSON representation
Native WorkManager: High-performance Flutter background Task Chains with zero-overhead. Harness the full power of Android WorkManager & iOS BGTaskScheduler using pure Kotlin/Swift Workers.
- Host: GitHub
- URL: https://github.com/brewkits/native_workmanager
- Owner: brewkits
- License: mit
- Created: 2026-02-05T00:11:24.000Z (3 months ago)
- Default Branch: main
- Last Pushed: 2026-04-14T05:10:09.000Z (14 days ago)
- Last Synced: 2026-04-14T06:31:08.573Z (13 days ago)
- Topics: android-workmanager, background, background-fetch, background-processing, background-tasks, battery-efficient, flutter, flutter-plugin, headless-execution, ios-background-tasks, kmp, kotlin, kotlin-multiplatform, memory-optimization, native-performance, performance-tuning, swift, task-chaining, task-scheduler, workmanager
- Language: JavaScript
- Homepage: https://pub.dev/packages/native_workmanager
- Size: 30.9 MB
- Stars: 9
- Watchers: 2
- Forks: 1
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- Contributing: CONTRIBUTING.md
- License: LICENSE
- Roadmap: ROADMAP.md
Awesome Lists containing this project
README
native_workmanager
Background tasks for Flutter — 25+ built-in workers, zero Flutter Engine overhead.
HTTP, file ops, image processing, encryption — all in pure Kotlin & Swift.
---
## The 30-second pitch
```dart
// Download → resize → upload — survives app kill, device reboot, low memory
await NativeWorkManager
.beginWith(TaskRequest(id: 'dl',
worker: NativeWorker.httpDownload(url: photoUrl, savePath: '/tmp/raw.jpg')))
.then(TaskRequest(id: 'resize',
worker: NativeWorker.imageResize(inputPath: '/tmp/raw.jpg',
outputPath: '/tmp/thumb.jpg', maxWidth: 512)))
.then(TaskRequest(id: 'upload',
worker: NativeWorker.httpUpload(url: uploadUrl, filePath: '/tmp/thumb.jpg')))
.named('photo-pipeline')
.enqueue();
```
No boilerplate. No native code to write. No `AndroidManifest.xml` changes. Each step retries independently — if the upload fails, only the upload retries.
---
## Quick Start
**1. Add the dependency:**
```yaml
dependencies:
native_workmanager: ^1.1.2
```
**2. Initialize once in `main()`:**
```dart
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await NativeWorkManager.initialize();
runApp(MyApp());
}
```
**3. Schedule a background task:**
```dart
await NativeWorkManager.enqueue(
taskId: 'daily-sync',
worker: NativeWorker.httpSync(url: 'https://api.example.com/sync'),
constraints: const Constraints(requiresNetwork: true),
);
```
**iOS only** — run once to configure `BGTaskScheduler` automatically:
```bash
dart run native_workmanager:setup_ios
```
---
## Why developers switch from `workmanager`
The dominant `workmanager` plugin spins up a **full Flutter Engine per background task**: ~50–100 MB RAM, up to 3 seconds cold start, a Dart isolate the OS kills the moment memory gets tight. On Xiaomi/Samsung/Huawei devices with aggressive battery optimization, the engine never even starts.
`native_workmanager` runs tasks as pure Kotlin coroutines and Swift async functions — **no engine, no isolate, no cold-start penalty**.
| | `workmanager` | `native_workmanager` |
|---|:---:|:---:|
| Memory per task | ~50–100 MB | **~2–5 MB** |
| Task startup | 1,500–3,000 ms | **< 50 ms** |
| Built-in HTTP workers | ❌ | ✅ (resumable download, chunked upload, parallel) |
| Built-in image workers | ❌ | ✅ (resize, crop, convert, thumbnail — EXIF-aware) |
| Built-in crypto workers | ❌ | ✅ (AES-256-GCM, SHA-256/512, HMAC) |
| Task chains (A→B→C) | ❌ | ✅ (persist across reboots) |
| Per-task progress stream | ❌ | ✅ |
| Survives device reboot | ✅ | ✅ |
| Custom Dart workers | ✅ | ✅ (opt-in via `DartWorker`) |
> **If you only do HTTP syncs and file ops, you probably don't need Dart workers at all.** Use the native workers directly — they're production-hardened and need zero engine overhead.
---
## 25+ Built-in Workers
All workers run natively. No Flutter Engine. No setup beyond `initialize()`.
| Category | Workers |
|----------|---------|
| **HTTP** | `httpDownload` (resumable), `httpUpload` (multipart), `parallelDownload` (chunked), `httpSync`, `httpRequest` |
| **Image** | `imageResize`, `imageCrop`, `imageConvert`, `imageThumbnail` — all EXIF-aware |
| **PDF** | `pdfMerge`, `pdfCompress`, `imagesToPdf` |
| **Crypto** | `cryptoEncrypt` (AES-256-GCM), `cryptoDecrypt`, `cryptoHash` (SHA-256/512), `hmacSign` |
| **File** | `fileCopy`, `fileMove`, `fileDelete`, `fileList` |
| **Storage** | `moveToSharedStorage` (Android MediaStore / iOS Files app) |
| **Real-time** | `webSocket` — Android |
---
## Track progress in real time
`enqueue()` returns a `TaskHandler` that streams progress and completion events for that specific task — no manual filtering required.
```dart
final handler = await NativeWorkManager.enqueue(
taskId: 'big-download',
worker: NativeWorker.httpDownload(
url: 'https://cdn.example.com/video.mp4',
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;
print(result.success ? 'Done!' : 'Failed: ${result.message}');
```
Or drop in the built-in widget:
```dart
TaskProgressCard(handler: handler, title: 'Downloading video')
```
---
## Task Chains
Chain workers into persistent pipelines. Each step only runs when the previous one succeeds, and the entire chain survives app kills and device reboots (SQLite-backed state).
```dart
await NativeWorkManager
.beginWith(TaskRequest(
id: 'download',
worker: NativeWorker.httpDownload(
url: 'https://cdn.example.com/report.pdf',
savePath: '/tmp/report.pdf',
),
))
.then(TaskRequest(
id: 'encrypt',
worker: NativeWorker.cryptoEncrypt(
inputPath: '/tmp/report.pdf',
outputPath: '/tmp/report.enc',
password: vaultKey,
),
))
.then(TaskRequest(
id: 'upload',
worker: NativeWorker.httpUpload(
url: 'https://vault.example.com/store',
filePath: '/tmp/report.enc',
),
))
.named('secure-report-pipeline')
.enqueue();
```
Use `.thenAll([...])` to run tasks in parallel, then continue the chain when all finish.
---
## Custom Dart Workers
For app-specific logic that must run in Dart, register a top-level function as a background worker:
```dart
@pragma('vm:entry-point')
Future syncHealthData(Map? input) async {
final userId = input?['userId'] as String?;
await uploadHealthMetrics(userId);
return true;
}
// Register once at startup
NativeWorkManager.registerDartWorker('health-sync', syncHealthData);
// Schedule it
await NativeWorkManager.enqueue(
taskId: 'sync-user-42',
worker: DartWorker(callbackId: 'health-sync', input: {'userId': '42'}),
);
```
Dart workers boot a headless Flutter isolate (~50 MB, 1–2 s cold start). The isolate is cached for 5 minutes so back-to-back tasks pay the boot cost only once. For HTTP and file tasks, use native workers instead.
---
## Platform Support
| Feature | Android | iOS |
|---------|:-------:|:---:|
| One-time tasks | ✅ | ✅ |
| Periodic tasks | ✅ | ✅ (BGAppRefresh) |
| Exact-time triggers | ✅ | ✅ |
| Task chains (persistent) | ✅ | ✅ |
| Network / charging constraints | ✅ | ✅ |
| Per-task progress stream | ✅ | ✅ |
| Foreground service (long tasks) | ✅ | — |
| Custom Dart workers | ✅ | ✅ |
| Min OS version | Android 8.0 (API 26) | iOS 14.0 |
---
## Migrating from `workmanager`
Most migrations take under 10 minutes. The conceptual model is the same; the API is a strict superset.
| `workmanager` | `native_workmanager` |
|---|---|
| `Workmanager().initialize(...)` | `NativeWorkManager.initialize()` |
| `Workmanager().registerOneOffTask(...)` | `NativeWorkManager.enqueue(worker: NativeWorker.httpSync(...))` |
| `Workmanager().registerPeriodicTask(...)` | `NativeWorkManager.enqueue(trigger: TaskTrigger.periodic(...))` |
| Custom Dart callback | `DartWorker(callbackId: ...)` |
See [Migration Guide](doc/MIGRATION_GUIDE.md) for a step-by-step walkthrough.
---
## Common Use Cases
📥 Resumable large file download
```dart
await NativeWorkManager.enqueue(
taskId: 'download-dataset',
worker: NativeWorker.httpDownload(
url: 'https://data.example.com/dataset.zip',
savePath: '/tmp/dataset.zip',
headers: {'Authorization': 'Bearer $token'},
allowResume: true,
),
constraints: const Constraints(requiresUnmeteredNetwork: true),
);
```
🔐 Encrypt & upload sensitive file
```dart
await NativeWorkManager
.beginWith(TaskRequest(
id: 'encrypt',
worker: NativeWorker.cryptoEncrypt(
inputPath: '/documents/report.pdf',
outputPath: '/tmp/report.enc',
password: securePassword,
),
))
.then(TaskRequest(
id: 'upload',
worker: NativeWorker.httpUpload(
url: 'https://vault.example.com/store',
filePath: '/tmp/report.enc',
),
))
.named('secure-backup')
.enqueue();
```
⏱ Periodic background sync
```dart
await NativeWorkManager.enqueue(
taskId: 'hourly-sync',
worker: NativeWorker.httpSync(url: 'https://api.example.com/sync'),
trigger: TaskTrigger.periodic(const Duration(hours: 1)),
constraints: const Constraints(requiresNetwork: true),
existingPolicy: ExistingTaskPolicy.keep,
);
```
📸 Photo backup pipeline
```dart
await NativeWorkManager
.beginWith(TaskRequest(
id: 'compress',
worker: NativeWorker.imageResize(
inputPath: photoPath,
outputPath: '/tmp/photo_compressed.jpg',
maxWidth: 1920,
quality: 85,
),
))
.then(TaskRequest(
id: 'upload',
worker: NativeWorker.httpUpload(
url: 'https://backup.example.com/upload',
filePath: '/tmp/photo_compressed.jpg',
),
))
.named('photo-backup')
.enqueue();
```
---
## Listen to task events
```dart
NativeWorkManager.events.listen((event) {
if (event.isStarted) {
print('▶ ${event.taskId} started (${event.workerType})');
return;
}
if (event.success) {
print('✅ ${event.taskId} — ${event.resultData}');
} else {
print('❌ ${event.taskId} — ${event.message}');
}
});
```
---
## Documentation
| Guide | |
|---|---|
| [Getting Started](doc/GETTING_STARTED.md) | Full setup walkthrough |
| [API Reference](doc/API_REFERENCE.md) | All public types and methods |
| [Migration from workmanager](doc/MIGRATION_GUIDE.md) | Switch in under 10 minutes |
| [iOS Setup Guide](doc/IOS_SETUP_GUIDE.md) | BGTaskScheduler details |
| [Architecture](doc/ARCHITECTURE_ANALYSIS.md) | How zero-engine execution works |
| [Security](doc/SECURITY.md) | SSRF, path traversal, data redaction |
---
## Support
- [GitHub Issues](https://github.com/brewkits/native_workmanager/issues) — bugs and feature requests
- [Discussions](https://github.com/brewkits/native_workmanager/discussions) — questions and community help
---
MIT License · Made by [BrewKits](https://brewkits.dev)
*Found this useful? A ⭐ on [GitHub](https://github.com/brewkits/native_workmanager) helps others discover it.*