ice_storage 1.3.0
ice_storage: ^1.3.0 copied to clipboard
Unified local storage for Flutter – secure, reactive, with image/file cache and Firestore offline sync for Firebase apps.
ice_storage
Librería de Flutter para gestión de datos locales de forma unificada, segura y reactiva. Permite manejar autenticación, preferencias de usuario, datos cifrados, caché de imágenes/archivos y copias de respaldo. Incluye un Firestore Offline Gateway que simplifica la sincronización con Firebase, ofreciendo soporte offline-first para que las aplicaciones se mantengan rápidas y funcionales aun sin conexión. Todo con una API consistente, encriptación opcional y señales reactivas en tiempo real.
Homepage: icedigital.pe
Desarrollado por: iCe-Digital
Instalación #
dependencies:
ice_storage: ^<latest_version>
main.dart:
import 'package:flutter/material.dart';
import 'package:ice_storage/ice_storage.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await IceStorage.init();
runApp(MyApp());
}
Guía rápida de uso #
Almacenamiento cifrado (claves, credenciales, etc.) #
// Guardar clave privada
await IceStorage.instance.secure.write('private_key', 'RSA2048_private_key_xyz');
// Leer clave privada
String? privateKey = await IceStorage.instance.secure.read<String>('private_key');
// Observar cambios (reactivo)
StreamBuilder<String?>(
stream: IceStorage.instance.secure.watch<String>('private_key'),
builder: (context, snapshot) {
return Text('Key: ${snapshot.data != null ? '***secured***' : 'No key'}');
},
);
// Eliminar clave privada
await IceStorage.instance.secure.delete('private_key');
Autenticación (MFA) #
// Guardar sesión
await IceStorage.instance.auth.save(
uid: 'user123',
token: 'jwt_token',
role: 'admin', // opcional
custom: {'deviceId': 'SM-A528B'}, // opcional
);
// Guardar código MFA con TTL
await IceStorage.instance.auth.saveMfaCode(
'123456',
validFor: Duration(minutes: 5),
);
// Verificar código ingresado
final isValid = IceStorage.instance.auth.verifyMfaCode(userInput);
// Observar autenticación (reactivo)
ValueListenableBuilder<bool>(
valueListenable: IceStorage.instance.auth.isAuthenticated,
builder: (context, isAuth, _) =>
isAuth ? const HomeScreen() : const LoginScreen(),
);
// Accesos directos
final uid = IceStorage.instance.auth.uid.value;
final token = IceStorage.instance.auth.token.value;
final role = IceStorage.instance.auth.role.value;
final hasMfa = IceStorage.instance.auth.isMfaCodeValid.value;
// Accesos directos (Opcional)
await IceStorage.instance.auth.setCustomField('deviceId', 'SM-A528B');
String deviceId = IceStorage.instance.auth.customFields.value['deviceId'];
// Cerrar sesión (limpia todo Auth)
await IceStorage.instance.auth.clearAuth();
Preferencias de usuario #
// Guardar preferencias
await IceStorage.instance.prefs.setBool('dark_mode', true);
await IceStorage.instance.prefs.setString('language', 'es');
await IceStorage.instance.prefs.setInt('fontSize', 16);
// Leer preferencias
bool? darkMode = IceStorage.instance.prefs.getBool('dark_mode');
String? language = IceStorage.instance.prefs.getString('language');
// Observar cambios (reactivo)
StreamBuilder<bool?>(
stream: IceStorage.instance.prefs.watch<bool>('dark_mode'),
builder: (context, snapshot) {
final isDark = snapshot.data ?? false;
return Switch(
value: isDark,
onChanged: (v) async {
await IceStorage.instance.prefs.setBool('dark_mode', v);
},
);
},
);
Listas dinámicas #
// Agregar a lista
await IceStorage.instance.prefs.addToList('favorites', 'item1');
// Leer lista
List<String>? favorites = await IceStorage.instance.prefs.read<List<String>>('favorites');
// Eliminar de lista
await IceStorage.instance.prefs.removeFromList('favorites', 'item1');
// Limpiar lista
await IceStorage.instance.prefs.clearList('favorites');
Mapas y objetos complejos #
// Guardar mapa
final userData = {
'name': 'Juan',
'age': 25,
'preferences': {'theme': 'dark', 'lang': 'es'}
};
await IceStorage.instance.prefs.write('user_data', userData);
// Leer mapa
Map<String, dynamic>? data = await IceStorage.instance.prefs.read<Map<String, dynamic>>('user_data');
// Observar cambios
StreamBuilder<Map<String, dynamic>?>(
stream: IceStorage.instance.prefs.watch<Map<String, dynamic>>('user_data'),
builder: (context, snapshot) {
final user = snapshot.data;
return Text('Usuario: ${user?['name']}');
},
);
Limpieza de datos #
// Limpiar solo datos seguros
await IceStorage.instance.clearByType(StorageType.secure);
// Limpiar solo preferencias
await IceStorage.instance.clearByType(StorageType.prefs);
// Limpiar solo imágenes
await IceStorage.instance.clearByType(StorageType.images);
// Limpiar todo
await IceStorage.instance.clearAll();
Estado de red #
IceStorage.instance.networkStatus: ConnectionStatus actual (connected/disconnected/noInternet)IceStorage.instance.connectionStatus: Stream
Imágenes de red #
// Descargar y cachear imagen
final bytes = await IceStorage.instance.images.downloadAndCacheImage(
'https://example.com/image.jpg',
headers: {'Authorization': 'Bearer $token'},
);
// Obtener imagen cacheada
final cachedBytes = await IceStorage.instance.images.getCachedImage(
'https://example.com/image.jpg',
);
// Verificar si está cacheada
bool isCached = await IceStorage.instance.images.isImageCached(
'https://example.com/image.jpg',
);
// Precargar múltiples imágenes
await IceStorage.instance.images.preloadImages([
'https://example.com/img1.jpg',
'https://example.com/img2.jpg',
]);
// Eliminar imagen específica
await IceStorage.instance.images.deleteImage(
'https://example.com/image.jpg',
);
// Eliminar múltiples imágenes
await IceStorage.instance.images.deleteImages([
'https://example.com/img1.jpg',
'https://example.com/img2.jpg',
]);
// Configurar duración del caché (opcional)
IceStorage.instance.images.configureCacheDuration(
Duration(days: 30),
);
Firestore Gateway (Sincronización Offline) #
// Inicializar después de Firebase.initializeApp()
await IceStorage.initFirestoreGateway(); // Modo smart (por defecto)
await IceStorage.initFirestoreGateway(offline: true); // Modo 100% offline
final gateway = IceStorage.instance.gateway!;
// CRUD Operations
await gateway.setDocument(
docRef: FirebaseFirestore.instance.collection('users').doc(),
data: {'name': 'Juan', 'age': 25},
);
await gateway.updateDocument(
docRef: FirebaseFirestore.instance.collection('users').doc('id'),
data: {'lastSeen': DateTime.now()},
);
await gateway.deleteDocument(
docRef: FirebaseFirestore.instance.collection('users').doc('id'),
);
// Streams reactivos
final stream = gateway.streamDocuments(
query: FirebaseFirestore.instance.collection('users').where('age', isGreaterThan: 18),
);
final docStream = gateway.streamDocument(
docRef: FirebaseFirestore.instance.collection('users').doc('userId'),
);
// Obtener documentos
final querySnapshot = await gateway.getDocuments(
query: FirebaseFirestore.instance.collection('users'),
);
final docSnapshot = await gateway.getDocument(
docRef: FirebaseFirestore.instance.collection('users').doc('userId'),
);
// Estado del gateway
StreamBuilder<FirestoreGatewayState>(
stream: gateway.state,
builder: (context, snapshot) {
final state = snapshot.data;
return Column(
children: [
Icon(state?.isOnline ?? false ? Icons.cloud_done : Icons.cloud_off),
if (state?.pendingWrites ?? 0 > 0)
Text('${state!.pendingWrites} pendientes'),
],
);
},
);
// Batch y transacciones
await gateway.batchWrite((batch) {
batch.set(doc1, data1);
batch.update(doc2, data2);
batch.delete(doc3);
});
await gateway.runTransaction<void>((transaction) async {
final doc = await transaction.get(docRef);
transaction.update(docRef, {'count': doc.data()?['count'] + 1});
});
// Forzar modo offline
await gateway.setMode(GatewayMode.offline);
// Utilidades
await gateway.waitForPendingWrites();
await gateway.clearCache();
Estado global y estadísticas #
// Observar estado global
StreamBuilder<StorageState>(
stream: IceStorage.instance.state,
builder: (context, snapshot) {
final state = snapshot.data;
return Column(
children: [
Text('Datos seguros: ${state?.secureDataCount}'),
Text('Preferencias: ${state?.prefsDataCount}'),
Text('Imágenes: ${state?.imageCacheCount}'),
],
);
},
);
// Obtener estadísticas
final stats = await IceStorage.instance.controller.getStats();
print('Total items: ${stats['total']['items']}');
Backup y restauración #
// Exportar todos los datos
final backup = await IceStorage.instance.exportAll();
// Guardar backup donde quieras (Firebase, archivo, etc.)
saveBackupSomewhere(backup);
// Restaurar datos
await IceStorage.instance.importData(backup);