Skip to main content

cache_network_media 2.0.0 copy "cache_network_media: ^2.0.0" to clipboard
cache_network_media: ^2.0.0 copied to clipboard

cached_network_image, but for SVG and Lottie too. Disk-cached network images, SVGs and Lottie animations with offline support, headers and download progress.

Cache Network Media #

cached_network_image, but for SVG and Lottie too.

Cache Network Media is a Flutter package that downloads network images, SVGs and Lottie animations once, stores them on disk, and shows them instantly (and offline) from then on.

SvgPicture.network (flutter_svg) and Lottie.network (lottie) do not keep a disk cache, so the same file is downloaded again on every cold start. This package adds that cache, with one widget for all three media types.

pub package GitHub CI Flutter

An animated bird loaded from the disk cache by Cache Network Media

Contents #

Why use it #

You get Details
One widget for three formats PNG, JPG, WebP, GIF and BMP images, SVG graphics and Lottie JSON animations
Persistent disk cache Files survive app restarts, so media loads without a network request after the first download
Offline support Cached media still shows with no connection. Expired copies are used when a refresh fails
Real-world requests Request headers for authenticated CDNs, a timeout, and download progress
One download per URL 20 list items showing the same avatar trigger a single download, over one shared HTTP client
List-friendly lazyLoading waits until an item scrolls into view. Rebuilds never reload the media
Cache control maxAge, maxCacheSizeBytes, prefetch, evict and clear
Pure Dart No Kotlin, Swift, Gradle or CocoaPods setup. Works on Android, iOS, macOS, Windows and Linux

How it compares #

cache_network_media cached_network_image SvgPicture.network Lottie.network
Images with disk cache ✅ ✅ ❌ ❌
SVG with disk cache ✅ ❌ ❌ ❌
Lottie with disk cache ✅ ❌ ❌ ❌
Works as an ImageProvider ✅ ✅ ❌ ❌

Install #

flutter pub add cache_network_media

Or add it to pubspec.yaml:

dependencies:
  cache_network_media: ^1.1.0

Then import it:

import 'package:cache_network_media/cache_network_media.dart';

Quick start #

Cached network image #

CacheNetworkMediaWidget.img(
  url: 'https://example.com/image.png',
  width: 200,
  height: 200,
  fit: BoxFit.cover,
  placeholder: const CircularProgressIndicator(),
  errorBuilder: (context, error, stackTrace) => const Icon(Icons.error),
)

Cached SVG #

CacheNetworkMediaWidget.svg(
  url: 'https://example.com/icon.svg',
  width: 100,
  height: 100,
  color: Colors.blue,
)

Cached Lottie animation #

CacheNetworkMediaWidget.lottie(
  url: 'https://example.com/animation.json',
  width: 300,
  height: 300,
  repeat: true,
)

As an ImageProvider #

CacheNetworkMediaImageProvider uses the same disk cache and works anywhere Flutter accepts an ImageProvider:

CircleAvatar(
  backgroundImage: CacheNetworkMediaImageProvider('https://example.com/avatar.png'),
)

Migrating from cached_network_image #

The widgets map one to one. Here is the most common case:

// Before
CachedNetworkImage(
  imageUrl: 'https://example.com/image.png',
  placeholder: (context, url) => const CircularProgressIndicator(),
  errorWidget: (context, url, error) => const Icon(Icons.error),
)

// After
CacheNetworkMediaWidget.img(
  url: 'https://example.com/image.png',
  placeholder: const CircularProgressIndicator(),
  errorBuilder: (context, error, stackTrace) => const Icon(Icons.error),
)
// Before
CircleAvatar(backgroundImage: CachedNetworkImageProvider(url))

// After
CircleAvatar(backgroundImage: CacheNetworkMediaImageProvider(url))
cached_network_image cache_network_media
CachedNetworkImage(imageUrl: ...) CacheNetworkMediaWidget.img(url: ...)
CachedNetworkImageProvider(url) CacheNetworkMediaImageProvider(url)
placeholder: (context, url) => ... placeholder: widget
progressIndicatorBuilder progressBuilder: (context, progress) => ...
errorWidget: (context, url, error) => ... errorBuilder: (context, error, stackTrace) => ...
httpHeaders headers
memCacheWidth, memCacheHeight memCacheWidth, memCacheHeight
DefaultCacheManager().emptyCache() CacheNetworkMedia.clear()
DefaultCacheManager().removeFile(url) CacheNetworkMedia.evict(url)
DefaultCacheManager().downloadFile(url) CacheNetworkMedia.prefetch(url)

Things to know when switching:

  • Files cached by cached_network_image are not reused. Each image downloads once more.
  • Your SVG and Lottie code can switch from SvgPicture.network(url) and Lottie.network(url) to CacheNetworkMediaWidget.svg(url: url) and CacheNetworkMediaWidget.lottie(url: url).

Common tasks #

Show download progress #

CacheNetworkMediaWidget.img(
  url: 'https://example.com/large-photo.jpg',
  progressBuilder: (context, progress) =>
      CircularProgressIndicator(value: progress.fraction),
)

progress.received and progress.total are in bytes. progress.fraction is null when the server sends no size, which shows the indeterminate animation. progressBuilder replaces placeholder while a download runs. It is not used when the file is already cached.

Load from a CDN that needs authentication #

CacheNetworkMediaWidget.img(
  url: 'https://cdn.example.com/private/avatar.png',
  headers: {'Authorization': 'Bearer $token'},
  timeout: const Duration(seconds: 10),
)

timeout defaults to 30 seconds and fails the download when the server stops responding. The cache is keyed by URL only, so a cached file is served whatever headers you pass.

Lazy-load long lists #

ListView.builder(
  itemCount: 100,
  itemBuilder: (context, index) => CacheNetworkMediaWidget.img(
    url: 'https://example.com/image$index.png',
    height: 200,
    lazyLoading: true, // starts loading when the item becomes visible
  ),
)

Set cache limits #

Set these once, before runApp. They apply to images, SVGs and Lottie files:

void main() {
  // Download again after 7 days. While offline, the expired copy is still shown.
  CacheNetworkMedia.maxAge = const Duration(days: 7);

  // Keep the disk cache under 200 MB, deleting least recently used files first.
  CacheNetworkMedia.maxCacheSizeBytes = 200 * 1024 * 1024;

  runApp(const MyApp());
}

Both default to null: files never expire and the cache has no size limit.

Prefetch, evict and clear #

// Download ahead of time, for example before the user goes offline
await CacheNetworkMedia.prefetch('https://example.com/onboarding.json');

// Remove one file, for example after the user changes their avatar
await CacheNetworkMedia.evict('https://example.com/avatar.png');

// Remove everything, for example on logout
await CacheNetworkMedia.clear();

If you use a custom cacheDirectory, pass the same directory to these methods.

Use a custom cache directory #

CacheNetworkMediaWidget.img(
  url: 'https://example.com/image.png',
  cacheDirectory: Directory('/path/to/your/cache'),
)

Save memory with thumbnails #

Decode large images at the size you display them. Values are in physical pixels:

CacheNetworkMediaWidget.img(
  url: 'https://example.com/photo.jpg',
  width: 100,
  height: 100,
  memCacheWidth: (100 * MediaQuery.devicePixelRatioOf(context)).round(),
)

With CacheNetworkMediaImageProvider, wrap it in ResizeImage(provider, width: 200).

Tint SVGs and control Lottie playback #

CacheNetworkMediaWidget.svg(
  url: 'https://example.com/icon.svg',
  colorFilter: const ColorFilter.mode(Colors.red, BlendMode.srcIn),
  semanticsLabel: 'App logo',
)

CacheNetworkMediaWidget.lottie(
  url: 'https://example.com/animation.json',
  repeat: false,
  reverse: true,
  frameRate: 60,
)

API reference #

Full generated docs: pub.dev/documentation/cache_network_media.

Parameters for every media type #

Parameter Type Description
url String Required. The network URL of the media
cacheDirectory Directory? Custom cache directory. Uses the app cache directory if null
headers Map<String, String>? HTTP headers sent with the download
timeout Duration? How long the server may stay silent before the download fails. Default 30 seconds
width, height double? Size of the widget
fit BoxFit? How the media fills its box
alignment AlignmentGeometry Alignment inside the box. AlignmentDirectional is supported
placeholder Widget? Shown while loading
progressBuilder Widget Function(BuildContext, DownloadProgress)? Shown while downloading. Replaces placeholder
errorBuilder Widget Function(BuildContext, Object, StackTrace?)? Shown when loading fails
onTap VoidCallback? Called when the media is tapped
lazyLoading bool Wait until the widget is visible before loading. Default false

Image parameters (.img) #

Parameter Type Default Description
color, colorBlendMode Color?, BlendMode? null Blend a color into the image
filterQuality FilterQuality medium Sampling quality
repeat ImageRepeat noRepeat How to paint uncovered areas
semanticLabel String? null Accessibility label
memCacheWidth, memCacheHeight int? null Decode at this size, in physical pixels
gaplessPlayback bool false Keep the old image while a new one loads

SVG parameters (.svg) #

Parameter Type Default Description
color Color? null Simple tint
colorFilter ColorFilter? null Advanced color filtering
theme SvgTheme? null SVG theme
semanticsLabel String? null Accessibility label

Lottie parameters (.lottie) #

Parameter Type Default Description
repeat bool true Loop the animation
reverse bool false Play in reverse
animate bool true Start immediately
frameRate double? null Custom frame rate
delegates LottieDelegates? null Custom delegates

CacheNetworkMedia #

Member Description
maxAge How long a file stays fresh. null means forever
maxCacheSizeBytes Disk cache size limit. null means unlimited
prefetch(url, {cacheDirectory, headers, timeout}) Download into the cache without showing
evict(url, {cacheDirectory}) Remove one file
clear({cacheDirectory}) Remove all cached files

How caching works #

  1. The widget asks for a URL.
  2. If a fresh copy is on disk, it is returned immediately.
  3. Otherwise the file is downloaded (once, even if many widgets ask for it at the same time), written to disk, and returned.
  4. If the copy is older than maxAge and the new download fails, the old copy is shown.

Where files are stored. Files go in a cache_network_media/ folder inside the directory returned by getApplicationCacheDirectory() from path_provider, so each platform uses its own app cache location. Each file is named after the SHA-1 hash of its URL with a .cache extension, so file names stay short and safe however long the URL is.

Safe writes. Downloads are written to a temporary file and renamed when complete, so a killed app never leaves a half-written file that looks like a cache hit.

See ARCHITECTURE.md for the full design.

Platform support #

Platform Status
Android ✅
iOS ✅
macOS ✅
Windows ✅
Linux ✅
Web ❌ The package uses dart:io and would need a separate storage backend

FAQ #

Does it cache Lottie and SVG files across app restarts? Yes. Images, SVGs and Lottie files are stored on disk and reused on the next launch.

Does it work offline? Yes, for anything that was downloaded before. Expired files are still shown when a refresh fails.

How do I clear the cache on logout? Call await CacheNetworkMedia.clear().

Can I use it with authenticated or signed URLs? Yes. Pass headers for token-based CDNs. Signed URLs work too, and the file name is a hash, so long query strings are fine. Because the cache is keyed by the full URL, a URL whose signature changes on every request is cached as a new file each time.

Why doesn't SvgPicture.network or Lottie.network cache to disk? They load the file over the network on every cold start and keep nothing on disk. This package wraps the same renderers (flutter_svg and lottie) and adds the disk cache.

Does it support Flutter web? Not yet. See Platform support.

Contributing and license #

Found a flaw, a bug or a missing feature? You are welcome to help. Open an issue to report it, or send a pull request with a fix. Contributions of any size are appreciated, from typo fixes to new features.

Read CONTRIBUTING.md first, then:

git clone https://github.com/D-extremity/cache_network_media.git
cd cache_network_media
flutter pub get
flutter test
flutter analyze
dart format --set-exit-if-changed .

More documentation: ARCHITECTURE.md · CHANGELOG.md.

MIT License. See LICENSE.

Created by @D-extremity. If this package helped you, star the GitHub repository, like it on pub.dev, or report an issue.

9
likes
160
points
506
downloads
screenshot

Documentation

API reference

Publisher

verified publishertheextremity.live

Weekly Downloads

cached_network_image, but for SVG and Lottie too. Disk-cached network images, SVGs and Lottie animations with offline support, headers and download progress.

Repository (GitHub)
View/report issues
Contributing

Topics

#cache #network #image #svg #lottie

License

MIT (license)

Dependencies

crypto, flutter, flutter_svg, lottie, path_provider, visibility_detector

More

Packages that depend on cache_network_media