Skip to content

Stratégies de Stockage Flutter

Drift est un ORM puissant pour SQLite avec génération de code type-safe.

dependencies:
drift: ^2.14.1
sqlite3_flutter_libs: ^0.5.15
path_provider: ^2.0.15
path: ^1.8.3
dev_dependencies:
drift_dev: ^2.14.1
build_runner: ^2.4.7

Exemple de table :

import 'package:drift/drift.dart';
@DataClassName('Todo')
class Todos extends Table {
IntColumn get id => integer().autoIncrement()();
TextColumn get title => text().withLength(min: 1, max: 50)();
TextColumn get content => text().named('body')();
IntColumn get category => integer().nullable()();
DateTimeColumn get createdAt => dateTime().withDefault(currentDateAndTime)();
}
@DriftDatabase(tables: [Todos])
class AppDatabase extends _$AppDatabase {
AppDatabase() : super(_openConnection());
@override
int get schemaVersion => 1;
// Requêtes
Future<List<Todo>> getAllTodos() => select(todos).get();
Future<Todo> getTodoById(int id) => (select(todos)..where((t) => t.id.equals(id))).getSingle();
Future<int> insertTodo(TodosCompanion todo) => into(todos).insert(todo);
Future<bool> updateTodo(Todo todo) => update(todos).replace(todo);
Future<int> deleteTodo(int id) => (delete(todos)..where((t) => t.id.equals(id))).go();
}

Base de données NoSQL rapide et légère, parfaite pour le stockage d’objets.

dependencies:
hive: ^2.2.3
hive_flutter: ^1.1.0
dev_dependencies:
hive_generator: ^2.0.1
build_runner: ^2.4.7

Configuration :

import 'package:hive_flutter/hive_flutter.dart';
@HiveType(typeId: 0)
class User extends HiveObject {
@HiveField(0)
String name;
@HiveField(1)
int age;
@HiveField(2)
List<String> hobbies;
User({required this.name, required this.age, required this.hobbies});
}
// Initialisation
await Hive.initFlutter();
Hive.registerAdapter(UserAdapter());
// Utilisation
final box = await Hive.openBox<User>('users');
// CRUD
await box.add(User(name: 'John', age: 25, hobbies: ['Reading']));
final users = box.values.toList();
await box.putAt(0, User(name: 'Jane', age: 30, hobbies: ['Swimming']));
await box.deleteAt(0);

Base de données ultra-rapide avec support des requêtes complexes.

dependencies:
isar: ^3.1.0+1
isar_flutter_libs: ^3.1.0+1
dev_dependencies:
isar_generator: ^3.1.0+1
build_runner: ^2.4.7

Exemple :

import 'package:isar/isar.dart';
@collection
class Contact {
Id id = Isar.autoIncrement;
@Index(type: IndexType.value)
String? name;
String? phone;
@Index()
List<String> tags = [];
}
// Initialisation
final isar = await Isar.open([ContactSchema]);
// CRUD
await isar.writeTxn(() async {
await isar.contacts.put(Contact()..name = 'John'..phone = '123-456-7890');
});
final contacts = await isar.contacts.where().nameContains('John').findAll();

Base de données orientée objet avec synchronisation.

dependencies:
objectbox: ^2.3.1
objectbox_flutter_libs: ^2.3.1
dev_dependencies:
objectbox_generator: ^2.3.1
build_runner: ^2.4.7
  1. SharedPreferences :

    • Préférences utilisateur
    • Paramètres simples
    • Tokens non-sensibles
    • Données < 1MB
  2. Flutter Secure Storage :

    • Tokens d’authentification
    • Mots de passe
    • Clés API
    • Données sensibles
  3. SQLite/sqflite :

    • Données relationnelles
    • Requêtes complexes
    • Intégrité référentielle
    • Applications CRUD
  4. Hive :

    • Données non-relationnelles
    • Performance élevée
    • Objects Dart directs
    • Cache local
  5. Isar/ObjectBox :

    • Applications complexes
    • Requêtes avancées
    • Synchronisation
    • Performance critique
abstract class LocalDataSource<T> {
Future<List<T>> getAll();
Future<T?> getById(String id);
Future<void> insert(T item);
Future<void> update(T item);
Future<void> delete(String id);
Future<void> clear();
}
class UserLocalDataSource implements LocalDataSource<User> {
final UserRepository _repository = UserRepository();
@override
Future<List<User>> getAll() => _repository.getAllUsers();
@override
Future<User?> getById(String id) => _repository.getUserById(int.parse(id));
@override
Future<void> insert(User user) async {
await _repository.insertUser(user);
}
@override
Future<void> update(User user) async {
await _repository.updateUser(user);
}
@override
Future<void> delete(String id) async {
await _repository.deleteUser(int.parse(id));
}
@override
Future<void> clear() async {
// Implémentation de la suppression de tous les utilisateurs
}
}
abstract class DataRepository<T> {
Future<List<T>> getAll();
Future<T?> getById(String id);
Future<void> save(T item);
Future<void> delete(String id);
}
class UserRepository implements DataRepository<User> {
final LocalDataSource<User> _localDataSource;
final RemoteDataSource<User> _remoteDataSource;
final CacheDataSource<User> _cacheDataSource;
UserRepository({
required LocalDataSource<User> localDataSource,
required RemoteDataSource<User> remoteDataSource,
required CacheDataSource<User> cacheDataSource,
}) : _localDataSource = localDataSource,
_remoteDataSource = remoteDataSource,
_cacheDataSource = cacheDataSource;
@override
Future<List<User>> getAll() async {
try {
// Essayer le cache d'abord
final cachedUsers = await _cacheDataSource.getAll();
if (cachedUsers.isNotEmpty) {
return cachedUsers;
}
// Ensuite la base locale
final localUsers = await _localDataSource.getAll();
if (localUsers.isNotEmpty) {
await _cacheDataSource.saveAll(localUsers);
return localUsers;
}
// Finalement le serveur
final remoteUsers = await _remoteDataSource.getAll();
await _localDataSource.saveAll(remoteUsers);
await _cacheDataSource.saveAll(remoteUsers);
return remoteUsers;
} catch (e) {
// Fallback sur le local en cas d'erreur
return await _localDataSource.getAll();
}
}
}
SolutionPerformanceComplexitéTaille donnéesRelationsSécurité
SharedPreferences⭐⭐⭐⭐⭐⭐⭐⭐< 1MB
Secure Storage⭐⭐⭐⭐⭐⭐< 100KB⭐⭐⭐⭐⭐
SQLite⭐⭐⭐⭐⭐Illimitée⭐⭐⭐⭐⭐⭐⭐
Hive⭐⭐⭐⭐⭐⭐⭐⭐⭐Grande⭐⭐⭐⭐
Isar⭐⭐⭐⭐⭐⭐⭐⭐Très grande⭐⭐⭐⭐⭐⭐
ObjectBox⭐⭐⭐⭐⭐⭐⭐Très grande⭐⭐⭐⭐⭐⭐
class MigrationService {
static Future<void> migrateFromSQLiteToHive() async {
// 1. Lire les données existantes de SQLite
final sqliteData = await SQLiteRepository().getAllUsers();
// 2. Initialiser Hive
await Hive.initFlutter();
final hiveBox = await Hive.openBox<User>('users');
// 3. Migrer les données
for (final user in sqliteData) {
await hiveBox.add(user);
}
// 4. Marquer la migration comme terminée
final prefs = await SharedPreferences.getInstance();
await prefs.setBool('migrated_to_hive', true);
}
static Future<bool> needsMigration() async {
final prefs = await SharedPreferences.getInstance();
return !(prefs.getBool('migrated_to_hive') ?? false);
}
}
  1. Sécurité : Toujours chiffrer les données sensibles
  2. Performance : Utiliser des index pour les requêtes fréquentes
  3. Migrations : Planifier les changements de schéma
  4. Sauvegarde : Implémenter des mécanismes de backup
  5. Tests : Tester toutes les opérations de persistance
  6. Architecture : Séparer les couches de données
  7. Monitoring : Surveiller les performances de stockage
class HybridStorageService {
final SharedPreferences _prefs;
final FlutterSecureStorage _secureStorage;
final Database _database;
final Box _hiveBox;
HybridStorageService({
required SharedPreferences prefs,
required FlutterSecureStorage secureStorage,
required Database database,
required Box hiveBox,
}) : _prefs = prefs,
_secureStorage = secureStorage,
_database = database,
_hiveBox = hiveBox;
// Configuration non-sensible
Future<void> saveUserPreference(String key, dynamic value) async {
if (value is bool) await _prefs.setBool(key, value);
if (value is int) await _prefs.setInt(key, value);
if (value is String) await _prefs.setString(key, value);
}
// Données sensibles
Future<void> saveSecureData(String key, String value) async {
await _secureStorage.write(key: key, value: value);
}
// Données relationnelles
Future<void> saveRelationalData(String table, Map<String, dynamic> data) async {
await _database.insert(table, data);
}
// Cache haute performance
Future<void> saveCacheData(String key, dynamic data) async {
await _hiveBox.put(key, data);
}
}

Cette approche modulaire permet de maintenir un code propre et de faciliter les changements de solutions de stockage selon l’évolution des besoins de l’application.