Asset Manager Library
A lightweight, testable Flutter/Dart library for managing offline assets.
Supports downloading, verifying, caching, and syncing files from REST or GraphQL endpoints.
Ideal for apps that require reliable offline asset persistence (e.g., games, media, travel).
Features
- Concurrent multi-file downloads
- Retry logic with exponential backoff
- Progress, completion, and failure callbacks
- Local caching under app documents directory (
<app-docs>/assets/<path>) - Syncs local DB with files on disk
- No native dependencies
- Works with REST or GraphQL backends (via
urlResolver)
Installation
Add to your pubspec.yaml:
dependencies:
dio: ^5.7.0
path_provider: ^2.1.3
path: ^1.9.0
dev_dependencies:
flutter_test:
sdk: flutter
test: ^1.25.0
dio_http_mock_adapter: ^0.6.1
mockito: ^5.4.4
Quick Start
Define Your AppAsset Model
Your asset model should look like:
class AppAsset {
final String id;
final String path;
final String? url;
final String? downloadUrl;
final int? totalSize;
AppAsset({
required this.id,
required this.path,
this.url,
this.downloadUrl,
this.totalSize,
});
factory AppAsset.fromJson(Map<String, dynamic> json) => AppAsset(
id: json['id'],
path: json['path'],
url: json['url'],
downloadUrl: json['downloadUrl'],
totalSize: json['totalSize'],
);
Map<String, dynamic> toJson() => {
'id': id,
'path': path,
'url': url,
'downloadUrl': downloadUrl,
'totalSize': totalSize,
};
}
Download Assets Using AssetLoader
await AssetLoader.downloadAssetList(
assets: myAssets,
urlResolver: (a) => a.url ?? a.downloadUrl ?? '',
concurrency: 3,
retryAttempts: 3,
onFileProgress: (asset, p) => print("${asset.path}: ${(p * 100).toStringAsFixed(1)}%"),
onFileCompleted: (asset, msg) => print(msg),
onFileFailed: (asset, err) => print("Failed ${asset.path}: $err"),
onOverallProgress: (done, total) => print("Progress: $done/$total"),
onAllCompleted: () => print("β
All done!"),
);
Files are saved to
<AppDocumentsDir>/assets/<asset.path>.
High-Level Use with AssetManagerDownloader
final downloader = AssetManagerDownloader()
..onBeforeAssetsDownloaded = () async => print("Preparing downloads...");
await downloader.downloadAssets(
myAssets,
onProgress: (progress, asset, msg) => print(msg),
onFileCompleted: (asset, msg) => print('OK: ${asset.path}'),
onFileFailed: (asset, err) => print('FAIL: ${asset.path} $err'),
onOverallProgress: (msg) => print(msg),
onAllCompleted: (msg) => print(msg),
onRetry: (msg, failed) => print('Retrying ${failed.length} assets...'),
);
This approach:
- Syncs with your local database (
LocalStorage). - Removes missing files from the DB.
- Tracks total bytes and overall progress.
π Check Required Assets
final allDownloaded = await downloader.isRequiredAssetsDownloaded();
if (!allDownloaded) {
print("Some assets are missing!");
}
Checks if all assets registered in your AssetRegister are downloaded.
Project Structure
lib/
βββ persistance/
β βββ file_handler.dart
βββ services/
β βββ asset_management/
β βββ asset_loader.dart
β βββ asset_downloader.dart
βββ register/
βββ asset_register.dart
Extending
- Checksum Verification:
Add ahashfield toAppAssetand verify file integrity after download (MD5/SHA-256). - Resume Support:
If your backend supports range requests, add theRangeheader for partial downloads.
Example: Integrate with a REST API
final response = await Dio().get("https://api.example.com/assets");
final assets = (response.data as List)
.map((a) => AppAsset.fromJson(a))
.toList();
await AssetLoader.downloadAssetList(
assets: assets,
urlResolver: (a) => a.url ?? '',
);
Utility Classes
- FileHandler: JSON cache handler with
checkFilesExist() - LocalStorage: Local DB wrapper for asset persistence
- AssetLoader: Core downloader, retry logic, progress events
- AssetManagerDownloader: High-level manager with DB + disk sync
Registering Assets
Register assets you want to use and access them from the registry.
The registry acts as a checklistβensuring all assets you need are available and downloaded to the correct paths.
You can register assets manually or automatically:
// Register a single asset
AssetRegister.instance.register("assetX", "assets/images/zz");
// Register multiple assets
AssetRegister.instance.registerAll({
"assetX": "assets/images/zz",
"assetY": "assets/images/yy",
});
To auto-register from a list of AppAsset objects (no manual registration required):
AssetRegister.instance.autoRegisterUsingAppAsset(myAssets);
Pros:
- Assets are automatically registered before download.
- With a consistent
AppAssetschema (possibly stored externally), you ensure only valid assets are downloaded.
Cons:
- If you donβt keep a record of required assets, you may lose reference in your codebase (but you can always get all registered keys).
- All assets must conform to the
AppAssetmodel.
License
MIT License
Β© 2025 Olamide Ogunlade
Libraries
- flutter_remote_asset_manager
- models/iserializable
- persistance/file_handler
- persistance/local_storage
- register/asset_register
- services/asset_management/abstract_asset_downloader
- services/asset_management/app_asset
- services/asset_management/asset_loader
- services/asset_management/background_task_manager
- utils/logger
- utils/md5_verifier