Basics

Speicher

Einleitung

Nylo Website v7 bietet ein leistungsstarkes Speichersystem ueber die Klasse NyStorage. Es verwendet unter der Haube flutter_secure_storage, um Daten sicher auf dem Geraet des Benutzers zu speichern.

import 'package:nylo_framework/nylo_framework.dart';

// Save a value
await NyStorage.save("coins", 100);

// Read a value
int? coins = await NyStorage.read<int>('coins'); // 100

// Delete a value
await NyStorage.delete('coins');

Werte speichern

Speichern Sie Werte mit NyStorage.save() oder dem storageSave()-Helfer:

// Using NyStorage class
await NyStorage.save("username", "Anthony");
await NyStorage.save("score", 1500);
await NyStorage.save("isPremium", true);

// Using helper function
await storageSave("username", "Anthony");

Gleichzeitig in Backpack speichern

Speichern Sie sowohl im persistenten Speicher als auch im In-Memory-Backpack:

await NyStorage.save('auth_token', 'abc123', inBackpack: true);

// Now accessible synchronously via Backpack
String? token = Backpack.instance.read('auth_token');

Werte lesen

Lesen Sie Werte mit automatischer Typkonvertierung:

// Read as String (default)
String? username = await NyStorage.read('username');

// Read with type casting
int? score = await NyStorage.read<int>('score');
double? rating = await NyStorage.read<double>('rating');
bool? isPremium = await NyStorage.read<bool>('isPremium');

// With default value
String name = await NyStorage.read('name', defaultValue: 'Guest') ?? 'Guest';

// Using helper function
String? username = await storageRead('username');
int? score = await storageRead<int>('score');

Werte loeschen

// Delete a single key
await NyStorage.delete('username');

// Delete and remove from Backpack too
await NyStorage.delete('auth_token', andFromBackpack: true);

// Delete multiple keys
await NyStorage.deleteMultiple(['key1', 'key2', 'key3']);

// Delete all (with optional exclusions)
await NyStorage.deleteAll();
await NyStorage.deleteAll(excludeKeys: ['auth_token']);

Storage Keys

Organisieren Sie Ihre Speicherschluessel in lib/config/storage_keys.dart:

final class StorageKeysConfig {
  // Auth key for user authentication
  static StorageKey auth = 'SK_AUTH';

  // Keys synced on app boot
  static syncedOnBoot() => () async {
    return [
      coins.defaultValue(0),
      themePreference.defaultValue('light'),
    ];
  };

  static StorageKey coins = 'SK_COINS';
  static StorageKey themePreference = 'SK_THEME_PREFERENCE';
  static StorageKey onboardingComplete = 'SK_ONBOARDING_COMPLETE';
}

StorageKey-Extensions verwenden

StorageKey ist ein Typedef fuer String und verfuegt ueber eine leistungsstarke Sammlung von Extension-Methoden:

// Save
await StorageKeysConfig.coins.save(100);

// Save with Backpack
await StorageKeysConfig.coins.save(100, inBackpack: true);

// Read
int? coins = await StorageKeysConfig.coins.read<int>();

// Read with default value
int? coins = await StorageKeysConfig.coins.fromStorage<int>(defaultValue: 0);

// Save/Read JSON
await StorageKeysConfig.coins.saveJson({"gold": 50, "silver": 200});
Map? data = await StorageKeysConfig.coins.readJson<Map>();

// Delete
await StorageKeysConfig.coins.deleteFromStorage();

// Delete (alias)
await StorageKeysConfig.coins.flush();

// Read from Backpack (synchronous)
int? coins = StorageKeysConfig.coins.fromBackpack<int>();

// Collection operations
await StorageKeysConfig.coins.addToCollection<int>(100);
List<int> allCoins = await StorageKeysConfig.coins.readCollection<int>();

JSON speichern/lesen

Speichern und Abrufen von JSON-Daten:

// Save JSON
Map<String, dynamic> user = {
  "name": "Anthony",
  "email": "anthony@example.com",
  "preferences": {"theme": "dark"}
};
await NyStorage.saveJson("user_data", user);

// Read JSON
Map<String, dynamic>? userData = await NyStorage.readJson("user_data");
print(userData?['name']); // "Anthony"

TTL (Time-to-Live)

Nylo Website v7 unterstuetzt das Speichern von Werten mit automatischem Ablauf:

// Save with 1 hour expiration
await NyStorage.saveWithExpiry(
  'session_token',
  'abc123',
  ttl: Duration(hours: 1),
);

// Read (returns null if expired)
String? token = await NyStorage.readWithExpiry<String>('session_token');

// Check remaining time
Duration? remaining = await NyStorage.getTimeToLive('session_token');
if (remaining != null) {
  print('Expires in ${remaining.inMinutes} minutes');
}

// Clean up all expired keys
int removed = await NyStorage.removeExpired();
print('Removed $removed expired keys');

Batch-Operationen

Effizientes Verarbeiten mehrerer Speicheroperationen:

// Save multiple values
await NyStorage.saveAll({
  'username': 'Anthony',
  'score': 1500,
  'level': 10,
});

// Read multiple values
Map<String, dynamic?> values = await NyStorage.readMultiple<dynamic>([
  'username',
  'score',
  'level',
]);

// Delete multiple keys
await NyStorage.deleteMultiple(['temp_1', 'temp_2', 'temp_3']);

Einleitung zu Collections

Collections ermoeglichen es Ihnen, Listen von Elementen unter einem einzelnen Schluessel zu speichern:

// Add items to a collection
await NyStorage.addToCollection("favorites", item: "Product A");
await NyStorage.addToCollection("favorites", item: "Product B");

// Read the collection
List<String> favorites = await NyStorage.readCollection<String>("favorites");
// ["Product A", "Product B"]

Zu einer Collection hinzufuegen

// Add item (allows duplicates by default)
await NyStorage.addToCollection("cart_ids", item: 123);

// Prevent duplicates
await NyStorage.addToCollection(
  "cart_ids",
  item: 123,
  allowDuplicates: false,
);

// Save entire collection at once
await NyStorage.saveCollection<int>("cart_ids", [1, 2, 3, 4, 5]);

Collection lesen

// Read collection with type
List<int> cartIds = await NyStorage.readCollection<int>("cart_ids");

// Check if collection is empty
bool isEmpty = await NyStorage.isCollectionEmpty("cart_ids");

Collection aktualisieren

// Update item by index
await NyStorage.updateCollectionByIndex<int>(
  0, // index
  (item) => item + 10, // transform function
  key: "scores",
);

// Update items matching a condition
await NyStorage.updateCollectionWhere<Map<String, dynamic>>(
  (item) => item['id'] == 5, // where condition
  key: "products",
  update: (item) {
    item['quantity'] = item['quantity'] + 1;
    return item;
  },
);

Aus Collection loeschen

// Delete by index
await NyStorage.deleteFromCollection<String>(0, key: "favorites");

// Delete by value
await NyStorage.deleteValueFromCollection<int>(
  "cart_ids",
  value: 123,
);

// Delete items matching a condition
await NyStorage.deleteFromCollectionWhere<Map<String, dynamic>>(
  (item) => item['expired'] == true,
  key: "coupons",
);

// Delete entire collection
await NyStorage.delete("favorites");

Backpack-Speicher

Backpack ist eine leichtgewichtige In-Memory-Speicherklasse fuer schnellen synchronen Zugriff waehrend der Benutzersitzung. Daten werden nicht persistiert, wenn die App geschlossen wird.

In Backpack speichern

// Using helper
backpackSave('user_token', 'abc123');
backpackSave('user', userObject);

// Using Backpack directly
Backpack.instance.save('settings', {'darkMode': true});

Aus Backpack lesen

// Using helper
String? token = backpackRead('user_token');
User? user = backpackRead<User>('user');

// Using Backpack directly
var settings = Backpack.instance.read('settings');

Aus Backpack loeschen

backpackDelete('user_token');

// Delete all
backpackDeleteAll();

Praktisches Beispiel

// After login, store token in both persistent and session storage
Future<void> handleLogin(String token) async {
  // Persist for app restarts
  await NyStorage.save('auth_token', token);

  // Also store in Backpack for quick access
  backpackSave('auth_token', token);
}

// In API service, access synchronously
class ApiService extends NyApiService {
  Future<User?> getProfile() async {
    return await network<User>(
      request: (request) => request.get("/profile"),
      bearerToken: backpackRead('auth_token'), // No await needed
    );
  }
}

Daten mit Backpack persistieren

In einem Aufruf sowohl im persistenten Speicher als auch in Backpack speichern:

// Save to both
await NyStorage.save('user_token', 'abc123', inBackpack: true);

// Now accessible via Backpack (sync) and NyStorage (async)
String? tokenSync = Backpack.instance.read('user_token');
String? tokenAsync = await NyStorage.read('user_token');

Speicher mit Backpack synchronisieren

Laden Sie beim App-Start den gesamten persistenten Speicher in Backpack:

// In your app provider
await NyStorage.syncToBackpack();

// With overwrite option
await NyStorage.syncToBackpack(overwrite: true);

Sessions

Sessions bieten benannten, In-Memory-Speicher zum Gruppieren zusammengehoeriger Daten (nicht persistiert):

// Create/access a session and add data
session('checkout')
    .add('items', ['Product A', 'Product B'])
    .add('total', 99.99)
    .add('coupon', 'SAVE10');

// Or initialize with data
session('checkout', {
  'items': ['Product A', 'Product B'],
  'total': 99.99,
});

// Read session data
List<String>? items = session('checkout').get<List<String>>('items');
double? total = session('checkout').get<double>('total');

// Get all session data
Map<String, dynamic>? checkoutData = session('checkout').data();

// Delete a single value
session('checkout').delete('coupon');

// Clear entire session
session('checkout').clear();
// or
session('checkout').flush();

Sessions persistieren

Sessions koennen mit dem persistenten Speicher synchronisiert werden:

// Save session to storage
await session('checkout').syncToStorage();

// Restore session from storage
await session('checkout').syncFromStorage();

Anwendungsfaelle fuer Sessions

Sessions sind ideal fuer:

  • Mehrstufige Formulare (Onboarding, Checkout)
  • Temporaere Benutzereinstellungen
  • Wizard-/Journey-Ablaeufe
  • Warenkorb-Daten

Model speichern

Die Model-Basisklasse bietet integrierte Speichermethoden. Wenn Sie einen key im Konstruktor definieren, kann sich das Model selbst speichern:

class User extends Model {
  String? name;
  String? email;

  // Define a storage key
  static StorageKey key = 'user';
  User() : super(key: key);

  User.fromJson(dynamic data) : super(key: key) {
    name = data['name'];
    email = data['email'];
  }

  @override
  Map<String, dynamic> toJson() => {
    "name": name,
    "email": email,
  };
}

Ein Model speichern

User user = User();
user.name = "Anthony";
user.email = "anthony@example.com";

// Save to persistent storage
await user.save();

// Save to both storage and Backpack
await user.save(inBackpack: true);

Ein Model zuruecklesen

User? user = await NyStorage.read<User>(User.key);

Mit Backpack synchronisieren

Laden Sie ein Model aus dem Speicher in Backpack fuer synchronen Zugriff:

bool found = await User().syncToBackpack();
if (found) {
  User? user = Backpack.instance.read<User>(User.key);
}

Model Collections

Speichern Sie Models in einer Collection:

User userAnthony = User();
userAnthony.name = 'Anthony';
await userAnthony.saveToCollection();

User userKyle = User();
userKyle.name = 'Kyle';
await userKyle.saveToCollection();

// Read back
List<User> users = await NyStorage.readCollection<User>(User.key);

StorageKey Extension-Referenz

StorageKey ist ein Typedef fuer String. Die NyStorageKeyExt-Extension bietet folgende Methoden:

Methode Rueckgabetyp Beschreibung
save(value, {inBackpack}) Future Wert im Speicher speichern
saveJson(value, {inBackpack}) Future JSON-Wert im Speicher speichern
read<T>({defaultValue}) Future<T?> Wert aus dem Speicher lesen
readJson<T>({defaultValue}) Future<T?> JSON-Wert aus dem Speicher lesen
fromStorage<T>({defaultValue}) Future<T?> Alias fuer read
fromBackpack<T>({defaultValue}) T? Aus Backpack lesen (synchron)
toModel<T>() T JSON-String in Model konvertieren
addToCollection<T>(value, {allowDuplicates}) Future Element zur Collection hinzufuegen
readCollection<T>() Future<List<T>> Collection lesen
deleteFromStorage({andFromBackpack}) Future Aus dem Speicher loeschen
flush({andFromBackpack}) Future Alias fuer deleteFromStorage
defaultValue<T>(value) Future Function(bool)? Standardwert setzen, wenn Schluessel leer ist (verwendet in syncedOnBoot)

Speicher-Ausnahmen

Nylo Website v7 bietet typisierte Speicher-Ausnahmen:

Ausnahme Beschreibung
StorageException Basis-Ausnahme mit Nachricht und optionalem Schluessel
StorageSerializationException Serialisierung des Objekts fuer den Speicher fehlgeschlagen
StorageDeserializationException Deserialisierung der gespeicherten Daten fehlgeschlagen
StorageKeyNotFoundException Speicherschluessel wurde nicht gefunden
StorageTimeoutException Speicheroperation hat das Zeitlimit ueberschritten
try {
  await NyStorage.read<User>('user');
} on StorageDeserializationException catch (e) {
  print('Failed to load user: ${e.message}');
  print('Expected type: ${e.expectedType}');
}

Legacy-Migration

Nylo Website v7 verwendet ein neues Envelope-Speicherformat. Wenn Sie von v6 aktualisieren, koennen Sie alte Daten migrieren:

// Call during app initialization
int migrated = await NyStorage.migrateToEnvelopeFormat();
print('Migrated $migrated keys to new format');

Dies konvertiert das Legacy-Format (separate _runtime_type-Schluessel) in das neue Envelope-Format. Die Migration kann sicher mehrfach ausgefuehrt werden - bereits migrierte Schluessel werden uebersprungen.