Mobile apps run in venue basements, warehouses and conference halls. Offline is the normal condition, not the exception.
Two storage layers
| Layer | Holds | Why |
|---|---|---|
flutter_secure_storage | Tokens | Encrypted at rest |
shared_preferences | Settings — last org, theme, layout | Small, non-sensitive |
hive | Cached records | Fast, structured, survives restarts |
Caching reads
Write through on every successful fetch, then serve from cache when the network is gone:
Future<List<Lead>> getLeads({bool forceRefresh = false}) async {
if (!forceRefresh && !await _isOnline()) {
return _cache.getLeads();
}
try {
final leads = await _service.list();
await _cache.saveLeads(leads);
return leads;
} catch (_) {
return _cache.getLeads(); // network failed — fall back
}
}Falling back on failure as well as on known-offline matters. Connectivity reports a network, not a working one — captive portals and dead uplinks both look online.
Detecting connectivity
Watch continuously rather than checking at launch, so recovery is automatic:
Connectivity().onConnectivityChanged.listen((result) {
final online = result != ConnectivityResult.none;
if (online) _syncQueue.flush();
});Queueing writes
Actions taken offline go into a queue and replay when connectivity returns. Each entry needs enough to retry independently — method, path, body, and a client-generated id so a retry does not create duplicates.
Replay in order, and drop an entry only once the server has accepted it.
A card payment must reach the processor, and a ticket scan must ask the server whether that ticket was already used at another door. Queueing either produces a wrong answer — a payment that did not happen, or a double entry. These wait for connectivity instead, and the UI should say so rather than appearing to succeed.
What to cache
Cache reference data that changes slowly — the product catalog, customer list, menu, event schedule, floor plan.
Do not cache anything where staleness is dangerous: live stock counts, ticket validity, queue position, payment state.
Clear on sign-out
Clear the cache along with the tokens. On a shared device, a cache that survives sign-out shows one user another's records.
Keeping the UI honest
Show offline state explicitly and label stale data. A user who knows they are offline will retry later; one who thinks a queued action completed will not.