A Flutter package that simultaneously downloads, caches, and streams remote content. Perfect for media players and any plugin that streams web content.

Motivation

The ability to simultaneously download and cache files remains a highly requested feature of video and audio playback plugins. By creating a local HTTP server, HttpCacheStream supports virtually any plugin that streams from web links. Unlike traditional caching solutions, HttpCacheStream works while the file is still downloading - allowing immediate playback of media files.

Features

  • Simultaneous Download and Streaming - Start playing media instantly while downloading
  • Persistent Caching - Cache files locally for offline playback
  • Range Request Support - Efficient seeking in media players
  • Resumable Downloads - Continue downloads after app restart
  • HTTP Server - Works with any media player supporting HTTP URLs
  • Custom Headers - Configure both request and response headers

Getting Started

Using http_cache_stream to simultaneously cache and stream a video file:

import 'package:http_cache_stream/http_cache_stream.dart';

// Initialize the cache manager
await HttpCacheManager.init();

// Create a stream for a specific URL
final sourceUrl = Uri.parse('https://example.com/video.mp4');
final cacheStream = HttpCacheManager.instance.createStream(sourceUrl);

// Get the local cache URL to pass to your media player
final cacheUrl = cacheStream.cacheUrl;
// Example output: http://127.0.0.1:4612/example.com/video.mp4

// Use with any player
final videoPlayerController = VideoPlayerController.network(cacheUrl);
await videoPlayerController.initialize();
videoPlayerController.play();

See the example project to learn how to use http_cache_stream with video_player, audioplayers, and just_audio

Platform configuration

Since http_cache_stream utilizes a localhost HTTP server, configuration is necessary to allow cleartext (non-HTTPS) connections:

iOS/macOS

Add the following to your projects Info.plist file:

<key>NSAppTransportSecurity</key>
<dict>
    <key>NSAllowsArbitraryLoads</key>
    <true/>
</dict>

Android:

Create android/app/src/main/res/xml/network_security_config.xml:

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
	<domain-config cleartextTrafficPermitted="true">
		<domain includeSubdomains="false">127.0.0.1</domain>
	</domain-config>
</network-security-config>

Reference the file in android/app/src/main/res/AndroidManifest.xml by adding the following entry under application:

    <application ... android:networkSecurityConfig="@xml/network_security_config">

See the example project for a full example.

Core Components

HttpCacheManager

The central manager for all cache streams:

// Initialize once
await HttpCacheManager.init();
final cacheManager = HttpCacheManager.instance;

// Configure global settings
cacheManager.config.requestHeaders[HttpHeaders.userAgentHeader] = 'MyApp/1.0';

// Create streams
final cacheStream = cacheManager.createStream(url);

// Manage cache
await cacheManager.deleteCache(); // Clear inactive cache

HttpCacheStream

Manages downloading, caching, and streaming for a specific URL:

final cacheStream = cacheManager.createStream(Uri.parse('https://example.com/file.mp3'));

// Start download explicitly (optional)
cacheStream.download();

// Get download progress
cacheStream.progressStream.listen((progress) {
  print('Download progress: ${(progress * 100).toStringAsFixed(1)}%');
});

cacheStream.dispose(); // Release when done

CacheMetadata

Each cached file has associated metadata stored in a companion .metadata file, which contains:

  • Original source URL
  • Response headers from the server
  • Additional cache information
// Get metadata for all cached files
final allMetadata = await cacheManager.cacheMetadataList();
final activeOnly = await cacheManager.cacheMetadataList(active: true);
final inactiveOnly = await cacheManager.cacheMetadataList(active: false);

// Get metadata for a specific URL
final metadata = cacheManager.getCacheMetadata(Uri.parse('https://example.com/video.mp4'));

// Delete cache files
await metadata?.cacheFiles.delete();

Metadata is automatically managed by HttpCacheStream, but you can also work with it directly to inspect or manipulate the cache without creating stream instances.

Advanced Usage

Cache Configuration

Configure both global and per-stream settings:

// Global configuration
final globalConfig = HttpCacheManager.instance.config;
globalConfig.requestHeaders[HttpHeaders.userAgentHeader] = 'MyApp/1.0';

// Per-stream configuration
final cacheStream = cacheManager.createStream(Uri.parse('https://example.com/file.mp3'));
cacheStream.config.copyCachedResponseHeaders = true;

Range Request Controls

When a client requests a byte range that's significantly ahead of what's currently cached, the library can initiate a separate direct connection to the source, rather than waiting for the sequential cache download to reach that position. The rangeRequestSplitThreshold setting controls this behavior by defining how many bytes ahead a request must be to trigger a separate connection.

// Set the threshold for creating a split download (in bytes)
cacheStream.config.rangeRequestSplitThreshold = 5 * 1024 * 1024; // 5MB

// Disable split downloads
cacheStream.config.rangeRequestSplitThreshold = null;

Cache Validation

// Check if cache is still valid
final isValid = await cacheStream.validateCache();
if (isValid == false) {
  // Cache is invalid, reset it
  await cacheStream.resetCache();
}

// Enable automatic validation of outdated cache
cacheStream.config.validateOutdatedCache = true;

Credits

http_cache_stream began as a custom implementation of just_audio's LockCachingAudioSource, a feature enabling simultaneous streaming and caching of audio files. Many thanks goes out to the developer and contributors of just_audio.

Libraries

http_cache_stream