transfer_manager 0.3.0
transfer_manager: ^0.3.0 copied to clipboard
A protocol-aware, crash-safe transfer engine for Dart and Flutter.
transfer_manager #
A protocol-aware transfer engine for Dart and Flutter. It provides one task model for uploads and downloads, a persistent queue, retries, progress and ETA, authentication renewal, integrity verification, and pluggable execution engines.
This repository currently contains the 0.3 foreground core. It does not claim native background execution: Android WorkManager/foreground service, iOS background URLSession, notifications, S3 multipart, and Flutter widgets belong in federated packages built on the contracts exposed here.
What works #
- Streamed HTTP multipart uploads
- TUS 1.0 uploads with persisted sessions and resumable chunks
- HTTP downloads with
.partfiles,RangeandIf-Range - Pause, resume, cancel, manual retry, and exponential automatic retry
- Global, upload/download, and per-host concurrency limits
- Priority ordering with FIFO inside one priority
- Atomic download completion
- SHA-256, SHA-512, and compatibility-only MD5 verification
- Fresh auth headers and single-flight refresh after HTTP 401
- In-memory storage and atomic JSON-file persistence
- Authorization and cookie header redaction in persisted records
- Atomic managed-source staging for uploads that must survive cache eviction
- Throttled progress with exponentially smoothed speed and ETA
Quick start #
import 'dart:io';
import 'package:transfer_manager/transfer_manager.dart';
Future<void> main() async {
final manager = TransferManager(
storage: JsonFileTransferStorage(File('.transfers/tasks.json')),
configuration: const TransferConfiguration(maxConcurrentTasks: 3),
);
await manager.initialize();
final task = await manager.enqueue(
DownloadRequest(
source: Uri.parse('https://example.com/report.pdf'),
destinationPath: 'downloads/report.pdf',
checksum: Checksum.sha256,
expectedChecksum: 'hex digest supplied by the server',
),
);
task.events.listen((event) {
print('${event.state}: ${event.progress.fraction}');
});
}
For a resumable upload, point TusUploadRequest at the server's TUS creation
endpoint. The engine records the returned upload URL and reconciles
Upload-Offset before resuming:
final task = await manager.enqueue(
TusUploadRequest(
sourcePath: 'videos/large.mp4',
endpoint: Uri.parse('https://uploads.example.com/files'),
chunkSize: 8 * 1024 * 1024,
metadata: const {'contentType': 'video/mp4'},
authScope: 'current-user',
),
);
Use authScope to persist an opaque credential lookup key. Do not put
short-lived credentials in request headers. A TransferAuthProvider is asked
for fresh headers immediately before execution and again after a 401.
Uploads selected from a cache or temporary picker location can be staged before enqueueing. The original remains untouched, while the managed copy is retained after failure and removed after completion or cancellation:
final manager = TransferManager(
configuration: const TransferConfiguration(
managedStoragePath: '/app-support/transfer_manager',
),
);
await manager.enqueue(
UploadRequest(
sourcePath: '/temporary-picker/video.mp4',
destination: Uri.parse('https://example.com/upload'),
sourcePolicy: UploadSourcePolicy.copyToManagedStorage,
),
);
Persistence and recovery #
Every meaningful transition is saved before its event is emitted. On
initialization, tasks interrupted in queued, preparing, running,
retryWaiting, or verifying are returned to the queue. Downloads retain
their .part file and continue with an HTTP range request when supported.
The bundled JSON store is intentionally simple and atomically replaces its
database file. Production Flutter integrations can implement TransferStorage
with SQLite without changing the manager API.
Platform boundary #
platformCapabilities currently reports foreground-only behavior. Native
packages should provide durable OS task identifiers, lifecycle reconnection,
network/charging constraints, and notifications, then report only the
capabilities actually supported on that platform.
See ROADMAP.md for the staged path to the full federated plugin.