A background file downloader and uploader for iOS, Android, MacOS, Windows and Linux
A robust, multi-platform background file transfer plugin for Flutter supporting background downloads, uploads, and data tasks across iOS, Android, MacOS, Windows, and Linux.
Uses native URLSession on iOS and MacOS, and DownloadWorker (WorkManager) / JobService (UIDT) on Android, ensuring transfers continue even when your app is in the background or terminated by the OS.
🌟 The Modern Transfer API (Recommended)
The easiest and most powerful way to use background_downloader is via the Transfer API.
On app startup (e.g. in main() or your top-level initState()), call FileDownloader().start(autoCleanDatabase: true) to activate persistent database tracking, automatically purge old task records, and reconcile transfers that completed or were interrupted while the app was suspended or closed. Then simply define a DownloadTask or UploadTask, start it using FileDownloader().transfers.start, and receive a reactive Transfer handle:
// 1. Activate database tracking & auto-cleanup on app launch (recommended)
await FileDownloader().start(autoCleanDatabase: true);
// 2. Configure notifications (recommended for userInitiated / UIDT tasks)
FileDownloader().configureNotification(
running: const TaskNotification('Downloading', '{filename}'),
complete: const TaskNotification('Complete', '{filename}'),
progressBar: true,
tapOpensFile: true,
);
// 3. Define the task with smart hints
final task = DownloadTask(
url: 'https://example.com/large_video.mp4',
filename: 'video.mp4',
transferHints: {TransferHint.userInitiated, TransferHint.largeFile},
);
// 4. Start the transfer
final transfer = await FileDownloader().transfers.start(task);
// 5. Directly await the completed File:
final file = await transfer.file;
print('Downloaded to: ${file.path}');
Why use Transfer?
- Awaitable Futures: Await
transfer.filefor the completedFile,transfer.resultfor theTaskStatusUpdate, ortransfer.responseBodyfor server response text. - Reactive UI Notifiers: Direct
ValueNotifierbindings for Flutter widgets:transfer.progressNotifier(clean0.0–1.0),transfer.statusNotifier,transfer.networkSpeedNotifier,transfer.timeRemainingNotifier, andtransfer.notificationTapNotifier. - Plug-and-Play Widgets: Pre-built UI components including
TransferProgressBar,TransferButton, andTransferListTile. - Direct Controls: Pause, resume, cancel, or allow cellular without managing task IDs:
await transfer.pause(),await transfer.resume(),await transfer.cancel(). - Batch Processing: Enqueue hundreds of transfers with aggregate progress using
FileDownloader().transfers.startAll(tasks, onProgress: ...). - Smart Auto-Tuning & Android 14+ UIDT: Use
TransferHint(userInitiated,largeFile,smallFile,lowPriority,useSuggestedFilename,binaryUpload) to configure optimal priority, Android 14+ UIDT, and pause resilience automatically. - Notification Tap Integration: React directly to user notification taps per transfer via
transfer.notificationTapNotifieror open downloaded files automatically withtapOpensFile: true. - Scoping & Isolation: Modularize downloads in plugins or sub-features with isolated namespaces using
FileDownloader.scoped('my_feature'). - Network Resilience: Automatic offline holding and resume, plus configurable stall detection (
stallTimeout).
👉 Read the complete Transfers Guide
🛠️ Lower-Level APIs
For specialized workflows or legacy integration, FileDownloader continues to provide direct lower-level methods:
Direct Awaitable Download (download)
Execute a task and wait for completion in a single call with inline callbacks:
final result = await FileDownloader().download(
task,
onProgress: (progress) => print('Progress: ${progress * 100}%'),
onStatus: (status) => print('Status: $status'),
);
if (result.status == TaskStatus.complete) {
print('Download finished!');
}
Queue & Event Streams (enqueue / enqueueAll)
For pipeline architectures where you monitor tasks centrally via a global stream or callbacks:
// 1. Listen centrally to task updates (typically in initState)
FileDownloader().updates.listen((update) {
switch (update) {
case TaskStatusUpdate():
print('Task ${update.task.taskId} status: ${update.status}');
case TaskProgressUpdate():
print('Task ${update.task.taskId} progress: ${update.progress * 100}%');
}
});
// 2. Start the downloader and activate persistent database tracking
FileDownloader().start();
// 3. Enqueue background tasks
final enqueued = await FileDownloader().enqueue(task);
📁 File Locations
To ensure file paths work robustly across platform restarts (especially on iOS and Android where container paths can change between app launches), the downloader uses a combination of BaseDirectory, directory (subdirectory) and filename:
BaseDirectory: One of.applicationDocuments,.temporary,.applicationSupport, or.applicationLibrary.directory: An optional subdirectory within the base directory.filename: The name of the file (orDownloadTask.suggestedFilename/'?'to use the server'sContent-Dispositionheader).
See File Storage for details on shared and scoped storage.
📚 Documentation Index
Check the Topic Index or specific guides:
- Transfers & High-Level API:
Transferhandles, reactive notifiers, UI widgets, batches, and scoping. - Downloads: Normal and parallel chunked downloads.
- Uploads: Multipart, binary, and multi-file uploads.
- Notifications: Native progress and completion notifications.
- Database & Central Monitoring: Event streams, callbacks, and persistent database tracking.
- Status & Progress Updates: Status lifecycles and progress events.
- File Storage & Locations: Scoped storage, app directories, moving files to Photos/Downloads.
- Lifecycle & Queue Management: Pausing, resuming, canceling, task queues, holding queues, and auth callbacks.
- Permissions: Android & iOS permissions setup.
- Server Requests & Cookies: Immediate HTTP requests and cookie handling.
- Optional Parameters: Headers, retries, priority, metadata, hints, and timeouts.
- Configuration: Timeouts, proxies, bypass TLS, etc.
- Working with URIs: Content URIs, URL Bookmarks, and platform pickers.
⚙️ Initial Setup
No setup is required for Windows or Linux.
Android
Requires Kotlin 2.1.0 or above. For modern Flutter projects, ensure your android/settings.gradle has:
plugins {
id "org.jetbrains.kotlin.android" version "2.1.0" apply false
}
iOS
No special setup is required. By default iOS requires HTTPS connections (see Apple ATS Configuration if HTTP is required).
MacOS
Add the client network entitlement to macos/Runner/DebugProfile.entitlements and macos/Runner/Release.entitlements:
<key>com.apple.security.network.client</key>
<true/>
⚠️ Platform Notes & Limitations
- iOS: Minimum iOS 14.0. Background transfers must complete within the system resource timeout (defaults to 4 hours, configurable via CONFIG.md).
- Android: Minimum API 21. Standard background tasks are limited to 9 minutes by WorkManager. To allow longer downloads, set
allowPause: true(orTransferHint.largeFile/userInitiated), which automatically resumes across 9-minute cycles, or setpriority: 0on Android 14+ to use UIDT (see parameters.md). - OS Termination: If the user forcefully swipes the app away from the iOS App Switcher or Android Recents, the OS may terminate background transfers without notification.
Libraries
- background_downloader
- A comprehensive background file downloader and uploader for iOS, Android, Desktop and Web