#💾 Stockage local avec SharedPreferences

SharedPreferences est un système de stockage local léger permettant de persister des données simples sous forme de paires clé-valeur. C’est une solution idéale pour sauvegarder les préférences utilisateur et les petites données d’ application.


#🤓 Vue d’ensemble

#Types de données supportés

  • String : Textes
  • int : Nombres entiers
  • double : Nombres décimaux
  • bool : Valeurs booléennes
  • List<String> : Listes de chaînes

#Implémentation native

  • Android : Fichier XML privé
  • iOS : NSUserDefaults
  • Web : localStorage
  • macOS : NSUserDefaults
  • Linux : Fichiers .pref
  • Windows : Registre Windows

#⚙️ Installation et configuration

#1. Ajout de la dépendance

dependencies:
  shared_preferences: ^2.2.2  # Vérifiez la dernière version sur pub.dev

#2. Import dans votre code

import 'package:shared_preferences/shared_preferences.dart';

#🌿 Utilisation basique

#1. Service de gestion des préférences

class PreferencesService {
  static late SharedPreferences _prefs;
  
  // Initialisation
  static Future<void> init() async {
    _prefs = await SharedPreferences.getInstance();
  }

  // Setters
  static Future<void> setString(String key, String value) async {
    await _prefs.setString(key, value);
  }
  
  static Future<void> setBool(String key, bool value) async {
    await _prefs.setBool(key, value);
  }
  
  static Future<void> setInt(String key, int value) async {
    await _prefs.setInt(key, value);
  }

  // Getters
  static String? getString(String key) {
    return _prefs.getString(key);
  }
  
  static bool? getBool(String key) {
    return _prefs.getBool(key);
  }
  
  static int? getInt(String key) {
    return _prefs.getInt(key);
  }

  // Suppression
  static Future<void> remove(String key) async {
    await _prefs.remove(key);
  }

  // Nettoyage complet
  static Future<void> clear() async {
    await _prefs.clear();
  }
}

#2. Gestionnaire de thème exemple

class ThemeManager extends ChangeNotifier {
  static const String _darkModeKey = 'isDarkMode';
  bool _isDarkMode = false;

  ThemeManager() {
    _loadTheme();
  }

  bool get isDarkMode => _isDarkMode;

  Future<void> _loadTheme() async {
    _isDarkMode = await PreferencesService.getBool(_darkModeKey) ?? false;
    notifyListeners();
  }

  Future<void> toggleTheme() async {
    _isDarkMode = !_isDarkMode;
    await PreferencesService.setBool(_darkModeKey, _isDarkMode);
    notifyListeners();
  }
}

#3. Gestionnaire de paramètres utilisateur

class UserSettings {
  static const String _volumeKey = 'volume';
  static const String _notificationsKey = 'notifications';
  static const String _languageKey = 'language';

  // Getters
  static Future<double> getVolume() async {
    return PreferencesService.getDouble(_volumeKey) ?? 0.5;
  }

  static Future<bool> getNotificationsEnabled() async {
    return PreferencesService.getBool(_notificationsKey) ?? true;
  }

  static Future<String> getLanguage() async {
    return PreferencesService.getString(_languageKey) ?? 'fr';
  }

  // Setters
  static Future<void> setVolume(double volume) async {
    await PreferencesService.setDouble(_volumeKey, volume);
  }

  static Future<void> setNotificationsEnabled(bool enabled) async {
    await PreferencesService.setBool(_notificationsKey, enabled);
  }

  static Future<void> setLanguage(String language) async {
    await PreferencesService.setString(_languageKey, language);
  }
}

#🧑‍💻 Exemples d’utilisation avancée

#1. Stockage d’objets simples

class UserPreferences {
  static Future<void> saveUser(User user) async {
    final prefs = await SharedPreferences.getInstance();
    await prefs.setString('userId', user.id);
    await prefs.setString('userName', user.name);
    await prefs.setInt('userAge', user.age);
  }

  static Future<User?> getUser() async {
    final prefs = await SharedPreferences.getInstance();
    final id = prefs.getString('userId');
    if (id == null) return null;

    return User(
      id: id,
      name: prefs.getString('userName') ?? '',
      age: prefs.getInt('userAge') ?? 0,
    );
  }
}

#2. Gestion d’onboarding

class OnboardingManager {
  static const String _hasCompletedOnboardingKey = 'hasCompletedOnboarding';

  static Future<bool> hasCompletedOnboarding() async {
    final prefs = await SharedPreferences.getInstance();
    return prefs.getBool(_hasCompletedOnboardingKey) ?? false;
  }

  static Future<void> markOnboardingComplete() async {
    final prefs = await SharedPreferences.getInstance();
    await prefs.setBool(_hasCompletedOnboardingKey, true);
  }
}

#👍 Bonnes pratique

#1. Gestion des clés

class PreferencesKeys {
  static const String theme = 'app_theme';
  static const String language = 'app_language';
  static const String userId = 'user_id';
  static const String sessionToken = 'session_token';
}

#2. Validation des données

Future<String> getValidatedString(String key, String defaultValue) async {
  final value = await PreferencesService.getString(key);
  return value?.isNotEmpty == true ? value! : defaultValue;
}

#3. Gestion des erreurs

Future<void> safeSetPreference(Future<void> Function() action) async {
  try {
    await action();
  } catch (e) {
    print('Erreur lors de la sauvegarde des préférences: $e');
    // Gérer l'erreur (retry, notification utilisateur, etc.)
  }
}

#🛑 Limitations et alternatives

#Limitations

  • Données non cryptées
  • Stockage limité aux types primitifs
  • Non adapté aux grandes quantités de données
  • Pas de support pour les requêtes complexes

#Alternatives selon les besoins

  1. Données sécurisées
    • flutter_secure_storage
    • encrypted_shared_preferences
  2. Données structurées
    • SQLite (via sqflite)
    • Hive
    • ObjectBox
  3. Grands volumes de données
    • Fichiers locaux
    • Base de données SQLite
  4. Données en temps réel
    • Firebase Realtime Database
    • Stream/BLoC pattern