flutter-caching — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited flutter-caching (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Apply the appropriate caching mechanism based on the data lifecycle and size requirements.
shared_preferences.sqflite, Drift, Hive CE, or Isar).path_provider.sync the Element tree with the engine.
FlutterEngine.Design repositories as the single source of truth, combining local databases and remote API clients.
#### Read Operations (Stream Approach) Yield local data immediately for fast UI rendering, then fetch remote data, update the local cache, and yield the fresh data.
Stream<UserProfile> getUserProfile() async* {
// 1. Yield local cache first
final localProfile = await _databaseService.fetchUserProfile();
if (localProfile != null) yield localProfile;
// 2. Fetch remote, update cache, yield fresh data
try {
final remoteProfile = await _apiClientService.getUserProfile();
await _databaseService.updateUserProfile(remoteProfile);
yield remoteProfile;
} catch (e) {
// Handle network failure; UI already has local data
}
}#### Write Operations Determine the write strategy based on data criticality:
database if the API call succeeds.
call. If the API call fails, flag the local record for background synchronization.
#### Background Synchronization Add a synchronized boolean flag to your data models. Keep the model immutable (Freezed): never mutate the flag in place. Produce a new instance with copyWith(synchronized: true) and write that back. Run a periodic background task (e.g., via workmanager or a Timer) to push unsynchronized local changes to the server.
#### File System Caching Use path_provider to locate the correct directory.
getApplicationDocumentsDirectory() for persistent data.getTemporaryDirectory() for cache data the OS can clear.Future<File> get _localFile async {
final directory = await getApplicationDocumentsDirectory();
return File('${directory.path}/cache.txt');
}#### SQLite Persistence Use sqflite for relational data caching. Always use whereArgs to prevent SQL injection.
Future<void> updateCachedRecord(Record record) async {
final db = await database;
await db.update(
'records',
record.toMap(),
where: 'id = ?',
whereArgs: [record.id], // NEVER use string interpolation here
);
}#### Image Caching Image I/O and decompression are expensive.
cached_network_image package to handle file-system caching of remote images.ImageProvider, override createStream() andresolveStreamForKey() instead of the deprecated resolve() method.
ImageCache.maxByteSize no longer automatically expands for large images. If loading imageslarger than the default cache size, manually increase ImageCache.maxByteSize or subclass ImageCache to implement custom eviction logic.
#### Scroll Caching When configuring caching for scrollable widgets (ListView, GridView, Viewport), use the scrollCacheExtent property with a ScrollCacheExtent object. Do not use the deprecated cacheExtent and cacheExtentStyle properties.
// Correct implementation
ListView(
scrollCacheExtent: const ScrollCacheExtent.pixels(500.0),
children: // ...
)
Viewport(
scrollCacheExtent: const ScrollCacheExtent.viewport(0.5),
slivers: // ...
)#### Widget Caching
operator == on Widget objects. It causes O(N²) behavior during rebuilds.operator == only on leaf widgets (no children) where comparing properties issignificantly faster than rebuilding, and the properties rarely change.
const constructors to allow the framework to short-circuit rebuilds automatically.To eliminate the non-trivial warm-up time of a FlutterEngine when adding Flutter to an existing Android app, pre-warm and cache the engine.
Application class.FlutterEngineCache.withCachedEngine in the FlutterActivity or FlutterFragment.// 1. Pre-warm in Application class
val flutterEngine = FlutterEngine(this)
flutterEngine.navigationChannel.setInitialRoute("/cached_route")
flutterEngine.dartExecutor.executeDartEntrypoint(DartEntrypoint.createDefault())
// 2. Cache the engine
FlutterEngineCache.getInstance().put("my_engine_id", flutterEngine)
// 3. Use in Activity/Fragment
startActivity(
FlutterActivity.withCachedEngine("my_engine_id").build(this)
)Note: You cannot set an initial route via the Activity/Fragment builder when using a cached engine. Set the initial route on the engine's navigation channel before executing the Dart entrypoint.
#### Workflow: Implementing an Offline-First Repository Follow these steps to implement a robust offline-first data layer.
synchronized boolean flag (default false).DatabaseService (SQLite/Hive) with CRUD operations.ApiClientService for network requests.Repository class combining both services.Stream<T> (yield local, fetch remote, update local, yield remote).synchronized flag).synchronized == false.#### Workflow: Pre-warming the Android FlutterEngine Follow these steps to cache the FlutterEngine for seamless Android integration.
Application class (create one if it doesn't exist and register in AndroidManifest.xml).FlutterEngine.navigationChannel.setInitialRoute().dartExecutor.executeDartEntrypoint().FlutterEngineCache.getInstance().put().FlutterActivity or FlutterFragment to use .withCachedEngine("id").~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.