resumable_downloader 0.1.0-dev.4 copy "resumable_downloader: ^0.1.0-dev.4" to clipboard
resumable_downloader: ^0.1.0-dev.4 copied to clipboard

Reliable Flutter downloads with multipart ranges, durable resume, scheduling, integrity checks, and authenticated restoration.

resumable_downloader #

A Flutter-first download manager for reliable foreground file transfers. V2 supports bounded concurrent files, multipart HTTP range downloads, durable resume, pause/resume, integrity checks, and authenticated restoration.

V2 #

The default library exports V2:

import 'package:resumable_downloader/resumable_downloader.dart';

Create a manager and enqueue a task:

final manager = DownloadManager(
  subdirectory: 'downloads',
  configuration: DownloadConfiguration(
    maxConcurrentDownloads: 3,
    maxConcurrentConnections: 6,
    maxConnectionsPerDownload: 4,
    minimumBytesPerPart: 8 * 1024 * 1024,
  ),
);

final task = manager.enqueue(
  DownloadRequest(
    url: Uri.parse('https://example.com/archive.zip'),
    fileName: 'archive.zip',
  ),
);

task.updates.listen((update) {
  print('${update.status}: ${update.receivedBytes}/${update.totalBytes}');
});

final file = await task.result;
await manager.dispose();

When the server honors byte ranges, V2 splits eligible files into ranges and writes them directly into one staged file. It falls back to one stream when a server ignores range requests. maxConcurrentDownloads bounds files, maxConcurrentConnections bounds all HTTP work, and maxConnectionsPerDownload bounds each file. maxRetries, retryDelay, and checkpointBytes control transient retries and durable progress checkpoints.

Task Controls #

await task.pause();
await task.resume();
await task.cancel();

Use DownloadStatus and DownloadRangeUpdate from task.updates to render aggregate and per-part progress. DownloadTask.result completes with the final file or fails with a typed DownloadException.

Tasks with an expectedSha256 or validator emit DownloadStatus.validating after all bytes arrive and before completion. The logical lifecycle is preparing, downloading, validating, then completed; retained existing outputs can move directly from preparing to validating. The validating update reports full byte progress with no active ranges.

validating was appended to DownloadStatus in 0.1.0-dev.4 so existing enum indices remain unchanged. Exhaustive switches must still add the new value. Pause is applied after successful validation and revalidates on resume. Cancel also takes effect after the validator returns and prevents finalization.

Existing Output And Deletion #

ExistingFilePolicy.resume is the default. A completed output is reused; replace removes it before downloading again; keepExisting reuses it; and fail reports a conflict.

final request = DownloadRequest(
  url: url,
  fileName: 'archive.zip',
  existingFilePolicy: ExistingFilePolicy.replace,
);

await manager.deleteArtifacts(request, cancelActive: true);

deleteArtifacts removes the request's V2 staged partial/manifest and, by default, its final output file.

Integrity #

V2 validates range lengths before finalization. Optionally require SHA-256:

final request = DownloadRequest(
  url: url,
  fileName: 'release.zip',
  expectedSha256: '64-character-lowercase-sha256-hex-digest',
);

On a checksum mismatch, V2 raises DownloadIntegrityException and discards the staged state rather than exposing a file with unverified contents.

Custom Validation #

Add an app-owned check when a checksum alone is not enough, such as signature, archive, media, or file-format verification:

final request = DownloadRequest(
  url: url,
  fileName: 'release.zip',
  expectedSha256: expectedDigest,
  validator: (data) async {
    return verifyReleaseSignature(data.file);
  },
);

The validator runs after configured SHA-256 validation. Return true to accept the file or false to reject it. data.file is a lightweight File handle, not a copy of the downloaded bytes, but it must be treated as read-only because V2 owns its lifecycle.

For a new transfer, a rejection deletes the staged file and manifest. V2 also validates retained resume and keepExisting outputs before returning them: resume deletes a rejected output and downloads it again, while keepExisting reports the rejection without deleting that output. replace removes an existing output before downloading and validating a fresh one; fail reports an existing-output conflict before validation.

V2 reports rejection through DownloadValidationException on both task.result and DownloadUpdate.error. The parent application owns the domain reason: throw DownloadValidationException from the callback to retain a specific explanation. Other callback errors are wrapped with that error as the exception's cause.

Validation callbacks are application code, so the package cannot forcibly interrupt an arbitrary callback future. The application should apply its own timeout when needed. A validation failure takes precedence over a simultaneous pause; cancellation prevents the file from being finalized once the callback settles.

Active requests with the same durable transfer identity share one task. The first request owns its validator and lifecycle; validators are intentionally not part of deduplication identity.

Authenticated Restoration #

V2 stores partial bytes and non-sensitive manifest metadata. It does not store headers, cookies, bearer tokens, or signed URLs. Provide an app-owned restorationId and resolve fresh credentials after restart:

final request = DownloadRequest(
  url: initialUrl,
  fileName: 'invoice.pdf',
  restorationId: 'invoice:8421',
  headers: {'Authorization': 'Bearer $token'},
);

await manager.restorePending((pending) async {
  final token = await secureStorage.read(key: 'token');
  final freshUrl = await api.invoiceDownloadUrl(pending.restorationId!);
  return DownloadRequest(
    url: freshUrl,
    fileName: pending.fileName,
    restorationId: pending.restorationId,
    headers: {'Authorization': 'Bearer $token'},
    expectedSha256: pending.expectedSha256,
    validator: validateInvoice,
  );
});

If a refreshed response no longer matches the staged entity validators, V2 discards stale staging and restarts safely. See durable restoration for details.

Validators are executable application code and are never persisted. Reattach them in the restoration resolver, just as you supply fresh URLs and headers.

Scope #

V2 is designed for foreground Flutter transfers. It does not promise that a download continues after the operating system terminates the app. Android and iOS background-transfer adapters are planned as separate optional packages.

Legacy API #

The former API remains available for maintenance compatibility through a separate entrypoint:

import 'package:resumable_downloader/resumable_downloader_legacy.dart' as legacy;

Legacy and V2 have independent models and managers. New integrations should use V2; do not mix the two APIs in one transfer flow.

Example #

The included Flutter example is a developer transfer lab. It exposes session limits, range-aware progress, speed, task controls, deletion, checksum input, and restart restoration scenarios.

Release Status #

V2 is available as a pub.dev pre-release and remains under active development. Track remaining stable-release work in doc/v2-publish-checklist.md.

9
likes
0
points
856
downloads

Publisher

verified publishershakyapurna.com.np

Weekly Downloads

Reliable Flutter downloads with multipart ranges, durable resume, scheduling, integrity checks, and authenticated restoration.

Repository (GitHub)
View/report issues

Topics

#downloader #resumable-download #dio #flutter #concurrency

License

unknown (license)

Dependencies

collection, crypto, dio, flutter, path_provider

More

Packages that depend on resumable_downloader