The ultimate Flutter plugin for caching network images, SVGs, and Lottie animations with persistent disk storage and offline support.
Tired of your app downloading the same images repeatedly? Want seamless offline support for your media assets? Cache Network Media provides a unified, efficient solution for caching all your network media in Flutter.
| Benefit | Description |
|---|---|
| 🚀 Faster Load Times | Media loads instantly from local cache after first download |
| 📴 Offline Support | Display cached media even without internet connection |
| 💾 Reduced Bandwidth | Download once, use forever - saves data for your users |
| 🎯 Unified API | One widget for images, SVGs, and Lottie - consistent syntax |
| 📁 Custom Cache Directory | Full control over where your cached files are stored |
| 🔧 Zero Configuration | Works out of the box with sensible defaults |
| 📱 Cross-Platform | Android, iOS with native platform channel support |
| Media Type | Supported | Caching Method | Use Case |
|---|---|---|---|
| PNG | ✅ | Binary | Photos, screenshots, graphics |
| JPG/JPEG | ✅ | Binary | Photos, compressed images |
| WebP | ✅ | Binary | Modern web images, animations |
| GIF | ✅ | Binary | Animated images |
| BMP | ✅ | Binary | Bitmap images |
| SVG | ✅ | Binary | Vector icons, logos, illustrations |
| Lottie JSON | ✅ | JSON File | Animations, micro-interactions |
| Feature | cache_network_media | Others |
|---|---|---|
| Image Caching | ✅ | ✅ |
| SVG Support | ✅ | ❌ |
| Lottie Support | ✅ | ❌ |
| Custom Cache Directory | ✅ | ❌ |
| Offline Support | ✅ | |
| Tap Gesture Support | ✅ | ❌ |
| Unified API | ✅ | ❌ |
| File-based Lottie Cache | ✅ | ❌ |
| Platform Channel Support | ✅ | |
| Privacy Manifest (iOS) | ✅ | ❌ |
| Swift Package Manager | ✅ |
Add to your pubspec.yaml:
dependencies:
cache_network_media: ^0.0.3Then run:
flutter pub getCacheNetworkMediaWidget.img(
url: 'https://example.com/image.png',
width: 200,
height: 200,
fit: BoxFit.cover,
placeholder: CircularProgressIndicator(),
onTap: () => debugPrint('Image tapped!'),
)CacheNetworkMediaWidget.svg(
url: 'https://example.com/icon.svg',
width: 100,
height: 100,
color: Colors.blue,
onTap: () => debugPrint('SVG tapped!'),
)CacheNetworkMediaWidget.lottie(
url: 'https://example.com/animation.json',
width: 300,
height: 300,
repeat: true,
animate: true,
onTap: () => debugPrint('Animation tapped!'),
)Take full control over where your cached files are stored. This is useful for:
- Organizing cached files by feature or user
- Managing cache size by clearing specific directories
- Sharing cache between different parts of your app
- Debugging by easily locating cached files
import 'dart:io';
// Use a custom directory for caching
final customDir = Directory('/path/to/your/cache');
CacheNetworkMediaWidget.img(
url: 'https://example.com/image.png',
cacheDirectory: customDir,
)Handle network failures gracefully:
CacheNetworkMediaWidget.img(
url: 'https://example.com/image.png',
placeholder: CircularProgressIndicator(),
errorBuilder: (context, error, stackTrace) {
return Column(
children: [
Icon(Icons.error, color: Colors.red),
Text('Failed to load image'),
],
);
},
)CacheNetworkMediaWidget.img(
url: 'https://example.com/image.png',
color: Colors.blue,
colorBlendMode: BlendMode.multiply,
filterQuality: FilterQuality.high,
)CacheNetworkMediaWidget.svg(
url: 'https://example.com/icon.svg',
colorFilter: ColorFilter.mode(Colors.red, BlendMode.srcIn),
theme: SvgTheme(currentColor: Colors.blue),
semanticsLabel: 'App logo',
)CacheNetworkMediaWidget.lottie(
url: 'https://example.com/animation.json',
repeat: false, // Play once
reverse: true, // Play in reverse
animate: true, // Auto-start
frameRate: 60.0, // Custom FPS
addRepaintBoundary: true, // Performance optimization
)Enable true lazy loading to defer media loading until the widget is actually visible in the viewport. Uses the visibility_detector package internally:
// Image with lazy loading
CacheNetworkMediaWidget.img(
url: 'https://example.com/image.png',
width: 400,
height: 300,
lazyLoading: true, // Loads only when visible
)
// SVG with lazy loading
CacheNetworkMediaWidget.svg(
url: 'https://example.com/icon.svg',
width: 100,
height: 100,
lazyLoading: true,
)
// Lottie with lazy loading
CacheNetworkMediaWidget.lottie(
url: 'https://example.com/animation.json',
width: 200,
height: 200,
lazyLoading: true,
repeat: true,
)How it works:
ListView.builder(
itemCount: 100,
itemBuilder: (context, index) {
return CacheNetworkMediaWidget.img(
url: 'https://example.com/image$index.png',
width: double.infinity,
height: 200,
lazyLoading: true, // Only loads when scrolled into view!
placeholder: const Center(
child: CircularProgressIndicator(),
),
);
},
)What Lazy Loading Does:
- ✅ Waits for widgets to scroll into the viewport before loading
- ✅ Works with vertical scrolling (ListView)
- ✅ Works with horizontal scrolling (ListView with scrollDirection: Axis.horizontal)
- ✅ Works with GridView and other scrollable widgets
- ✅ Only starts network request when widget becomes visible
- ✅ Saves bandwidth by not loading off-screen media
- ✅ Reduces memory usage significantly
Benefits:
- ⚡ Faster initial page load (only loads visible items)
- 💾 Dramatically reduced memory usage (no off-screen loading)
- 📶 Lower bandwidth consumption (loads on-demand)
- 🔋 Better battery life
- 📱 Smooth scrolling performance
- 🎯 Perfect for long lists and grids
Technical Details:
- Uses
visibility_detectorpackage for viewport detection - Triggers loading when
visibleFraction > 0(even partially visible) - Automatically handles both horizontal and vertical scrolling
- Minimal performance overhead
| Parameter | Type | Description |
|---|---|---|
url |
String |
Required. The network URL of the media |
cacheDirectory |
Directory? |
Custom directory for caching. Uses platform default if null |
width |
double? |
Width of the widget |
height |
double? |
Height of the widget |
fit |
BoxFit? |
How to inscribe the media into the allocated space |
alignment |
AlignmentGeometry |
How to align the media within its bounds |
placeholder |
Widget? |
Widget shown while loading |
errorBuilder |
Function? |
Builder for error widget |
onTap |
VoidCallback? |
Callback when widget is tapped |
| Parameter | Type | Default | Description |
|---|---|---|---|
color |
Color? |
null | Color to blend with image |
colorBlendMode |
BlendMode? |
null | Blend mode for color |
filterQuality |
FilterQuality |
medium | Quality of image sampling |
repeat |
ImageRepeat |
noRepeat | How to paint uncovered portions |
semanticLabel |
String? |
null | Accessibility label |
| Parameter | Type | Default | Description |
|---|---|---|---|
color |
Color? |
null | Simple color tinting |
colorFilter |
ColorFilter? |
null | Advanced color filtering |
theme |
SvgTheme? |
null | SVG theme for styling |
clipBehavior |
Clip |
hardEdge | How to clip content |
| 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 FPS |
delegates |
LottieDelegates? |
null | Custom delegates |
┌─────────────────────────────────────────────────────────────┐
│ Cache Flow Diagram │
├─────────────────────────────────────────────────────────────┤
│ │
│ Request URL ──► Check Cache ──► Cache Hit? ──► Yes ──► │
│ │ │ Return │
│ │ │ Cached │
│ │ ▼ │
│ │ No │
│ │ │ │
│ │ ▼ │
│ │ Download from │
│ │ Network │
│ │ │ │
│ │ ▼ │
│ │ Save to Cache │
│ │ │ │
│ │ ▼ │
│ └─────────────────────► Return Media │
│ │
└─────────────────────────────────────────────────────────────┘
| Media Type | Storage Format | Location |
|---|---|---|
| Images | .cache_image binary |
cache_network_media/ |
| SVG | .cache_image binary |
cache_network_media/ |
| Lottie | .json file |
cache_network_media/lottie/ |
| Platform | Status | Notes |
|---|---|---|
| Android | ✅ | Full support with method channels |
| iOS | ✅ | Swift Package Manager + Privacy Manifest |
| Web | 🚧 | Coming soon |
| macOS | 🚧 | Coming soon |
| Windows | 🚧 | Coming soon |
| Linux | 🚧 | Coming soon |
- Use appropriate image sizes - Don't load 4K images for thumbnails
- Leverage custom cache directories - Organize cache by feature for easier management
- Set dimensions when known - Provide
widthandheightto avoid layout shifts - Use
addRepaintBoundary- Enabled by default for Lottie, improves performance - Handle errors gracefully - Always provide an
errorBuilderfor production apps
// Before (cached_network_image)
CachedNetworkImage(
imageUrl: 'https://example.com/image.png',
placeholder: (context, url) => CircularProgressIndicator(),
errorWidget: (context, url, error) => Icon(Icons.error),
)
// After (cache_network_media)
CacheNetworkMediaWidget.img(
url: 'https://example.com/image.png',
placeholder: CircularProgressIndicator(),
errorBuilder: (context, error, stackTrace) => Icon(Icons.error),
)We welcome contributions! Please read our Contributing Guidelines before submitting a PR.
# Clone the repository
git clone https://github.com/D-extremity/cache_network_media.git
# Install dependencies
flutter pub get
# Run tests
flutter test
# Check formatting
dart format --set-exit-if-changed .
# Run analyzer
flutter analyzeMIT License - see LICENSE for details.
Created with ❤️ by @D-extremity
If this package helped you, please:
- ⭐ Star the GitHub repository
- 👍 Like on pub.dev
- 🐛 Report issues on GitHub Issues
Cache Network Media - Making network media caching simple since 2025