Skip to content

Downloads

Full story: the eight-part downloads deep dive.

A title is an HLS stream — a playlist pointing at a few thousand 4-second .ts segments plus one 16-byte AES key. “Downloading a film” means copying every one of those files to disk and rewriting the playlists to point at the copies. Each file becomes its own task for the background_downloader package; the app’s DownloadManager watches tasks finish and turns that into progress. Only once the disk proves every file is present does it write the local playlists and mark the title complete.

Android iOS
Task becomes a WorkManager job a background URLSession download
Feeding rate holding queue of 8 system-managed
Keeps going when app backgrounds via WorkManager + the app’s own foreground service the system’s background transfer; Dart may not be running
Quotas to respect background job quotas, 6-hour dataSync limit resource timeout

Almost all the complexity exists because phones don’t want apps running in the background, and a two-hour film on a shaky connection outlasts both operating systems’ patience.

When something goes wrong there are four layers that catch it — package retries, settlement, the stall watchdog, and cold-start reconciliation. The rule everywhere is: re-queue exactly the files missing on disk, never blindly restart the download. User actions: pause, resume, retry, cancel.

Download state lives in more places than you’d expect — Hive (CacheContentEntity), the disk layout itself, the package database, and native preferences — plus a status state machine and a startup reconciliation sequence. Before changing where state lives, read State, storage and startup and Operating and extending (logs, adb recipes, tests, tuning knobs, known limitations).