gsd_utilities 0.0.42
gsd_utilities: ^0.0.42 copied to clipboard
Flutter utilities for config management, local storage, and file uploads to DOCUframe.
GSD-Utilities #
Dieses Paket bietet umfassende Utility-Funktionen für Flutter-Anwendungen mit plattformübergreifender Konfigurationsverwaltung, LocalStorage mit Cross-Tab-Events, fortschrittlicher Datei-Upload-Funktionalität und DOCUframe-Integration. Es ermöglicht die strukturierte Verwaltung von Anwendungsdaten sowohl für Web- als auch für Mobile/Desktop-Plattformen.
Features #
- Plattformübergreifende Konfigurationsverwaltung: Automatische Plattformauswahl zwischen Web und Mobile/Desktop
- Sichere Datenpersistierung: Web mit verschlüsseltem LocalStorage, Mobile/Desktop mit FlutterSecureStorage
- LocalStorage mit Events: Cross-Tab-Kommunikation über JavaScript Interop
- URI-Management: Browser-URI-Manipulation
- Web-Benachrichtigungen: Browser-Notification-API mit Berechtigungsmanagement und Browser-Erkennung
- File Upload System: Real-time Fortschrittsverfolgung mit Byte-Level-Genauigkeit
- Bildverarbeitung: Automatische Bilderkennung und Größenanpassung
- Batch-Upload: Mehrere Dateien gleichzeitig hochladen
- DOCUframe Integration: Enterprise-Funktionen für DOCUframe-Systeme
- Event-basierte Architektur: Benachrichtigungen bei Datenänderungen
- TypeScript-kompatibel: JavaScript Interop für Web-Plattformen
- Memory-effizient: Automatisches Cleanup und Ressourcenverwaltung
Installation #
Fügen Sie das Paket in Ihrer pubspec.yaml hinzu:
dependencies:
gsd_utilities: [version]
Führen Sie anschließend flutter pub get aus, um das Paket zu installieren.
Nutzung #
Konfigurationsmanagement #
Erstellen Sie eine Konfigurationsklasse und verwalten Sie sie automatisch:
import 'package:gsd_utilities/gsd_utilities.dart';
// Eigene Konfigurationsklasse erstellen
class AppConfig extends GSDBaseConfig {
String? serverUrl;
int? timeout;
bool? debugMode;
AppConfig({this.serverUrl, this.timeout, this.debugMode});
@override
String toJson() {
return '{"serverUrl": ${serverUrl != null ? '"$serverUrl"' : 'null'}, '
'"timeout": $timeout, "debugMode": $debugMode}';
}
@override
void loadFromJson(String jsonString) {
final data = jsonDecode(jsonString);
serverUrl = data['serverUrl'];
timeout = data['timeout'];
debugMode = data['debugMode'];
}
@override
GSDBaseConfig createInstance() => AppConfig();
}
// Konfiguration laden und verwalten
final configManager = GSDConfigManager(key: "app_config");
final configResult = await configManager.loadConfig(AppConfig());
if (configResult.isSuccess && configResult.config != null) {
print('Konfiguration geladen: ${configResult.config!.serverUrl}');
} else {
print('Konfiguration konnte nicht geladen werden: ${configResult.log}');
}
ConfigStore (feldbasiert, prozesssicher) #
Der GSDConfigStore ist der Nachfolger des GSDConfigManager für Apps, die mehrfach
parallel auf einem Gerät laufen (mehrere Fenster, Browser-Tabs, Notification-Prozess)
und sich eine Konfiguration teilen. Statt eines JSON-Blocks ist jedes Feld ein
eigener Key; zwei Prozesse, die verschiedene Felder ändern, überschreiben sich nicht
mehr. Jedes Feld deklariert, ob es im sicheren Speicher (secure: true) oder im
öffentlichen Speicher liegt. Der alte GSDConfigManager bleibt unverändert erhalten.
import 'package:gsd_utilities/gsd_utilities.dart';
// Ein Eintrag einer Collection, z.B. ein Account
class AccountConfig extends GSDConfigItem {
AccountConfig(super.id) {
declareAll([name, username, password, sessionId]);
}
final name = GSDConfigValue<String>('name', defaultValue: '');
final username = GSDConfigValue<String>('username', defaultValue: '');
final password = GSDConfigOptionalValue<String>('password', secure: true);
final sessionId = GSDConfigOptionalValue<String>('sessionId', secure: true);
}
// Die Konfiguration: Felder und Collections im Konstruktor registrieren
class AppConfig extends GSDConfig {
AppConfig() {
declareAll([autoLogin, selectedTheme, lastAccount]);
collection(accounts);
}
final autoLogin = GSDConfigValue<bool>('autoLogin', defaultValue: false);
final selectedTheme = GSDConfigValue<String>('selectedTheme', defaultValue: 'system');
final lastAccount = GSDConfigOptionalValue<String>('lastAccount');
final accounts = GSDConfigCollection<AccountConfig>('accounts', AccountConfig.new);
}
// Auf dem Desktop das SQLite-Backend für SharedPreferencesAsync registrieren,
// unter Windows auch das für FlutterSecureStorage, bevor die App ihr erstes
// SharedPreferencesAsync() erzeugt oder ein Secret liest (am Anfang von
// main). forPlatform macht das auch, erreicht aber nur spätere Zugriffe.
if (!kIsWeb) {
switch (defaultTargetPlatform) {
case TargetPlatform.windows:
await GSDSqliteSharedPreferencesPlatform.register();
await GSDSqliteSecureStoragePlatform.register();
case TargetPlatform.macOS:
case TargetPlatform.linux:
await GSDSqliteSharedPreferencesPlatform.register();
default:
break;
}
}
// Store für die Plattform bauen (SharedPreferences + Secure Storage; auf dem
// Desktop SQLite-Backend und Dateilock im App-Support-Verzeichnis).
final store = await GSDConfigStoreFactory.forPlatform();
// Laden. Beim ersten Mal werden die alten Blöcke des GSDConfigManager
// (Key "config" / "config_secure"; bis 0.0.34 lag der öffentliche Block im
// sicheren Speicher unter "config") über den Hook übernommen. Ist ein alter
// Block gerade nicht lesbar (iOS vor dem ersten Entsperren), wird die
// Migration verschoben (result.migrationDeferred) und beim nächsten load
// nachgeholt; bis dahin angelegte Collection-Einträge bleiben erhalten.
final config = AppConfig();
final result = await store.load(config, migrate: (config, legacy) async {
final json = legacy.publicJson ?? {};
await config.autoLogin.set(json['autoLogin'] ?? false);
for (final entry in (json['accounts'] as List? ?? [])) {
final account = AccountConfig(entry['uuid']);
await account.name.set(entry['name'] ?? '');
await account.password.set(legacy.secureJson?[entry['uuid']]?['password']);
await config.accounts.add(account);
}
});
print(result.log);
// Schreiben: jeder set() schreibt genau einen Key unter dem Lock
await config.selectedTheme.set('dark');
await config.accounts.byId('a1')?.sessionId.set('abc');
// Mehrere Felder unter einem Lock
await store.batch(config, () async {
await config.autoLogin.set(true);
await config.lastAccount.set('a1');
});
// Anderer Prozess hat geschrieben? Frisch lesen:
await store.reload(config);
Wichtige Regeln:
- Felder registrieren:
declare/declareAllundcollectionmüssen im Konstruktor aufgerufen werden, sonst werden die Felder weder geladen noch geschrieben. GSDConfigValue<T>hat immer einen Default,GSDConfigOptionalValue<T>liefertnull, solange nichts gespeichert ist.set(null)löscht den Key.- Secrets werden nur geschrieben, wenn die App sie explizit setzt. Ein leeres Secret
löscht den Key. Kann der sichere Speicher nicht gelesen werden (z.B. iOS vor dem ersten
Entsperren), steht der Fehler in
result.secureErrorundfeld.loadError; es wird nie ein leeres Secret zurückgeschrieben. - Ids von Items dürfen nur
A-Z a-z 0-9 _ -enthalten (UUIDs passen); Feldnamen nurA-Z a-z 0-9 _. - Keys:
<namespace>.<feld>,<namespace>.<collection>(Index der Ids) und<namespace>.<collection>.<id>.<feld>. - Testen ohne Plugins:
GSDConfigStore(values: GSDConfigMemoryValueStore(), secrets: GSDConfigMemorySecretStore(), lock: GSDConfigInProcessLock()).
LocalStorage mit Cross-Tab-Events #
Überwachen Sie LocalStorage-Änderungen zwischen Browser-Tabs:
// LocalStorage Manager erstellen
final localStorageManager = GSDLocalStorageManager();
// Storage-Events überwachen (nur Web)
localStorageManager.storageChanged.subscribe((GSDWebLocalStorageEventArgs args) async {
print('Storage geändert von anderem Tab:');
print('Key: ${args.key}, Neuer Wert: ${args.value}');
});
// Daten schreiben und lesen
localStorageManager.writeData('user_settings', '{"theme": "dark"}');
String settings = localStorageManager.readData('user_settings');
print('Geladene Einstellungen: $settings');
URI-Management mit Browser History API #
Verwalten Sie Browser-URIs und Query-Parameter ohne Seitenreload:
// URI Manager erstellen
final uriManager = GSDUriManager();
// Aktuelle Browser-URI abrufen
Uri currentUri = uriManager.getCurrentUri();
print('Aktuelle URI: $currentUri');
// Query-Parameter verwalten
uriManager.setQueryParameter('page', '1');
uriManager.setQueryParameter('filter', 'active');
// Mehrere Parameter gleichzeitig setzen
uriManager.setQueryParameters({
'category': 'flutter',
'sort': 'date',
'view': 'grid'
});
// Parameter lesen
String? currentPage = uriManager.getQueryParameter('page');
Map<String, String> allParams = uriManager.getAllQueryParameters();
// Parameter entfernen
uriManager.removeQueryParameter('filter');
// Alle Parameter zurücksetzen
uriManager.resetUri();
// Browser-Titel ändern
uriManager.updateTitle('Meine Flutter App - Seite 1');
// Zu neuer URI navigieren
uriManager.navigateToUri(Uri.parse('https://example.com/newpage?tab=settings'));
URI-Manager Features #
// State-Management über URI
class SearchPage extends StatefulWidget {
@override
_SearchPageState createState() => _SearchPageState();
}
class _SearchPageState extends State<SearchPage> {
final GSDUriManager _uriManager = GSDUriManager();
@override
void initState() {
super.initState();
// State aus URI laden
_loadStateFromUri();
}
void _loadStateFromUri() {
final params = _uriManager.getAllQueryParameters();
setState(() {
searchQuery = params['q'] ?? '';
selectedCategory = params['category'] ?? 'all';
currentPage = int.tryParse(params['page'] ?? '1') ?? 1;
});
}
void _updateSearch(String query) {
// State in URI speichern
_uriManager.setQueryParameter('q', query);
_uriManager.setQueryParameter('page', '1'); // Reset zur ersten Seite
_uriManager.updateTitle('Suche: $query');
setState(() {
searchQuery = query;
currentPage = 1;
});
}
void _changeCategory(String category) {
_uriManager.setQueryParameter('category', category);
_uriManager.setQueryParameter('page', '1');
setState(() {
selectedCategory = category;
currentPage = 1;
});
}
}
Web-Benachrichtigungen mit Browser-Erkennung #
Senden Sie native Browser-Benachrichtigungen mit automatischer Browser-Erkennung:
import 'package:gsd_utilities/gsd_utilities.dart';
// Notification Helper erstellen
final notificationHelper = GSDNotificationsHelper();
// Browser-Information abrufen
print('Chrome Browser: ${notificationHelper.isChromeBrowser}');
print('Firefox Browser: ${notificationHelper.isFirefoxBrowser}');
print('Edge Browser: ${notificationHelper.isEdgeBrowser}');
print('Safari Browser: ${notificationHelper.isSafariBrowser}');
// Berechtigungsstatus prüfen
String permission = notificationHelper.notificationPermission;
print('Aktueller Status: $permission'); // 'default', 'granted', oder 'denied'
bool canSend = notificationHelper.isNotificationPermissionGranted;
bool isDenied = notificationHelper.isNotificationPermissionDenied;
bool isDefault = notificationHelper.isNotificationPermissionDefault;
// Berechtigung anfordern
if (notificationHelper.isNotificationPermissionDefault) {
notificationHelper.requestNotificationPermission();
// Nach kurzer Verzögerung Status prüfen
await Future.delayed(Duration(milliseconds: 500));
if (notificationHelper.isNotificationPermissionGranted) {
print('Berechtigung erteilt!');
}
}
// Benachrichtigung senden
if (notificationHelper.isNotificationPermissionGranted) {
notificationHelper.showNotification(
'GSD Utilities',
'Benachrichtigung erfolgreich gesendet!'
);
}
// Ressourcen aufräumen
notificationHelper.dispose();
Notification Features #
class NotificationService {
final GSDNotificationsHelper _notificationHelper = GSDNotificationsHelper();
// Berechtigung initialisieren
Future<bool> initializeNotifications() async {
if (_notificationHelper.isNotificationPermissionDefault) {
_notificationHelper.requestNotificationPermission();
// Warten auf Benutzer-Entscheidung
await Future.delayed(Duration(seconds: 1));
}
return _notificationHelper.isNotificationPermissionGranted;
}
// Status-Updates senden
void sendStatusUpdate(String title, String message) {
if (_notificationHelper.isNotificationPermissionGranted) {
_notificationHelper.showNotification(title, message);
}
}
// Browser-spezifische Behandlung
void handleBrowserSpecific() {
if (_notificationHelper.isChromeBrowser) {
// Chrome-spezifische Features
print('Chrome Browser erkannt - alle Features verfügbar');
} else if (_notificationHelper.isSafariBrowser) {
// Safari hat einige Einschränkungen
print('Safari Browser - eingeschränkte Notification-Features');
}
}
void dispose() {
_notificationHelper.dispose();
}
}
File Upload mit Fortschrittsverfolgung #
Laden Sie Dateien mit Real-time-Fortschrittsanzeige hoch:
import 'package:gsd_restapi/docuframe_api.dart';
// DOCUframe-API erstellen
final DOCUframeApi api = DOCUframeApi(
configuration: RestApiDOCUframeConfig(
appKey: 'GSD-DFApp',
userName: 'username',
appNames: ['app1'],
serverUrl: 'https://server.com',
alias: 'db',
),
);
// Upload Manager mit der Documents-Gruppe erstellen
final uploadManager = DOCUframeUploadManager(api.v1.documents);
// Dateien für Upload vorbereiten
List<GSDUploadFile> files = [
GSDUploadFile.fromPath('/path/to/document.pdf'),
GSDUploadFile.fromPath('/path/to/image.jpg'),
];
// Upload mit Fortschrittsverfolgung starten
await for (GSDUploadProgress progress in uploadManager.uploadFiles(files)) {
print('Gesamt-Fortschritt: ${progress.percentage}%');
print('Abgeschlossene Dateien: ${progress.completedFiles.length}/${progress.totalFiles}');
for (int i = 0; i < progress.uploadFileProgresses.length; i++) {
final fileProgress = progress.uploadFileProgresses[i];
print('Datei ${i + 1}: ${fileProgress.percentage}% - Status: ${fileProgress.status}');
}
if (progress.isFinished) {
print('Alle Uploads abgeschlossen!');
break;
}
}
Event-Handling #
// Konfigurationsänderungen überwachen
config.configChangedEvent.subscribe((args) async {
print('Konfiguration wurde automatisch gespeichert');
});
// Account-Änderungen überwachen
account.accountChanged.subscribe((args) async {
print('Account-Daten wurden geändert');
});
Konfigurationsarchitektur #
Das Paket verwendet eine plattformspezifische Konfigurationsarchitektur:
Web-Plattform #
- LocalStorage: Browser-basierte Datenpersistierung
- AES-Verschlüsselung: Sichere Speicherung sensibler Daten
- Storage-Events: Cross-Tab-Kommunikation über JavaScript Interop
Mobile/Desktop-Plattform #
- FlutterSecureStorage: Systemspezifische sichere Speicherung
- Platform-native: Verwendet OS-eigene Sicherheitsmechanismen
ConfigStore-Backends je Plattform #
| Plattform | Öffentliche Werte | Secrets | Lock |
|---|---|---|---|
| Windows | SharedPreferences mit SQLite-Backend (GSDSqliteSharedPreferencesPlatform: gsd_shared_preferences.db im App-Support-Verzeichnis, WAL, kein Prozess-Cache) |
FlutterSecureStorage mit SQLite-Backend (GSDSqliteSecureStoragePlatform: gsd_secure_storage.db, jeder Eintrag einzeln DPAPI-verschlüsselt) |
Dateilock (RandomAccessFile.lock) neben der Datenbank |
| macOS, Linux | SharedPreferences mit SQLite-Backend (wie Windows) | FlutterSecureStorage (Keychain, libsecret) | Dateilock neben der Datenbank |
| Android, iOS | SharedPreferences | FlutterSecureStorage | In-Process |
| Web | localStorage (Klartext) | FlutterSecureStorage (WebCrypto AES-GCM, nur im sicheren Kontext) | Web Locks API (im unsicheren Kontext In-Process) |
Überall liegen die öffentlichen Werte in SharedPreferencesAsync. Auf dem Desktop (Windows,
macOS, Linux) wird die Plattform-Implementierung des Plugins getauscht: die Plugins für Windows
und Linux halten alle Werte im Prozess-Cache und schreiben bei jedem Set die ganze JSON-Datei neu,
wodurch parallel laufende Prozesse (mehrere Fenster, Notification-Prozess) sich gegenseitig
überschreiben. macOS läuft für ein einheitliches Verhalten ebenfalls über SQLite.
GSDSqliteSharedPreferencesPlatform.register() ersetzt es durch eine SQLite-Datenbank ohne
Cache; das gilt dann für alle SharedPreferencesAsync-Objekte der App, die danach erzeugt
werden. Die bisherigen Werte des Plugins werden nicht übernommen; nur der alte
Konfigurationsblock des GSDConfigManager wird für die Migration von dort gelesen.
Secrets bleiben unter macOS und Linux im Plugin (Keychain, libsecret): dort liegt jeder Eintrag
einzeln im System-Dienst und ist damit prozesssicher.
Für Secrets gilt unter Windows dasselbe: flutter_secure_storage_windows hält alle Secrets in
einer DPAPI-Datei und schreibt sie bei jedem Zugriff komplett neu. Zwei Prozesse verlieren dabei
gegenseitig Werte, und liest einer eine halb geschriebene Datei, löscht das Plugin sie samt aller
Secrets. GSDSqliteSecureStoragePlatform.register() ersetzt es: jedes Secret ist eine eigene,
einzeln per DPAPI (Benutzerkontext) verschlüsselte Zeile in gsd_secure_storage.db. Ein nicht
entschlüsselbarer Eintrag wirft GSDSecretUnreadableException und betrifft nur sich selbst.
Die Registrierung gilt für jeden Nutzer von FlutterSecureStorage in der App (auch
gsd_encryption). Die bisherigen Einträge des Plugins werden nicht übernommen; nur der alte
Secret-Block des GSDConfigManager wird für die Migration von dort gelesen. Die alte Datei
bleibt unverändert.
Grenzen des Locks: Der Lock sichert getrennte Prozesse gegeneinander ab (mehrere Fenster,
zweite App-Instanz, Kindprozesse). Mehrere Isolates desselben Prozesses, etwa ein
Notification-Handler im Hintergrund-Isolate, sind nur unter Windows gegeneinander gesichert:
unter macOS und Linux gilt der fcntl-Dateilock pro Prozess, auf Android und iOS gibt es nur
den In-Process-Lock pro Isolate. Einzelne set-Aufrufe bleiben trotzdem sicher (ein Key,
atomar im Plugin); nur add/remove an Collections (Lesen-Ändern-Schreiben des Index) und
die einmalige Migration können sich zwischen Isolates überholen. Auf Android nutzt
SharedPreferencesAsync standardmäßig Jetpack DataStore, das selbst nicht für mehrere
Prozesse ausgelegt ist; getrennte Android-Prozesse (android:process) sind daher nicht
abgesichert.
Der Self-Test im Example (example/integration_test/config_store_test.dart, in der App unter
„ConfigStore Self-Test“) prüft mehrere Store-Instanzen auf jeder Plattform und unter Windows
zusätzlich echte Kindprozesse (dart run-Kinder im integration_test, die Example-EXE als zweite
App-Instanz im Screen).
Der Screen startet Kopien der EXE auf der Platte: nach flutter test integration_test ist das ein
Test-Build, die App also vor dem Screen-Test per flutter run neu starten (kein Hot Restart).
File Upload Features #
Unterstützte Dateitypen #
- Dokumente: PDF, DOC, DOCX, TXT, etc.
- Bilder: PNG, JPEG, GIF, WebP (mit automatischer Komprimierung)
- Archive: ZIP, RAR, etc.
- Web-Dateien: Direkte Browser-Upload-Unterstützung
Upload-Funktionen #
// Bildkomprimierung konfigurieren
final uploadFile = GSDUploadFile.fromPath('/path/to/large_image.jpg');
uploadFile.setResolution(GSDUploadImageResolution(percentage: 75)); // 75% der Originalgröße
// Upload-Status überwachen
if (fileProgress.status == GSDUploadFileStatus.completed) {
print('Upload erfolgreich! Server-ID: ${fileProgress.result?.oid}');
} else if (fileProgress.status == GSDUploadFileStatus.failed) {
print('Upload fehlgeschlagen: ${fileProgress.result?.error}');
}
DOCUframe Integration #
Spezielle Enterprise-Funktionen für DOCUframe-Systeme:
// Account-Konfiguration
final account = DOCUframeAccount(
'Mein Account',
'https://docuframe.server.com',
'account_alias',
'username'
);
account.setDatabaseName('production_db');
// Account-Serialisierung
Map<String, dynamic> accountData = account.toJson();
DOCUframeAccount restoredAccount = DOCUframeAccount.fromJson(accountData);
Error-Handling #
Das Paket bietet umfassende Fehlerbehandlung:
try {
final result = await configManager.loadConfig(AppConfig());
if (!result.isSuccess) {
print('Fehler beim Laden: ${result.error}');
print('Debug-Log: ${result.log}');
}
} catch (e) {
print('Unerwarteter Fehler: $e');
}
Performance und Memory Management #
- Automatisches Cleanup: Event-Listener werden automatisch entfernt
- Memory-effizient: Große Dateien werden in Chunks verarbeitet
- Background-Processing: Uploads laufen im Hintergrund
- Platform-optimiert: Plattformspezifische Optimierungen
API-Design #
Das Paket folgt dem Prinzip der sauberen Architektur:
- ✅
GSDConfigManager- Hauptklasse für Konfigurationsverwaltung (JSON-Block) - ✅
GSDConfigStore,GSDConfigStoreFactory- Feldbasierter, prozesssicherer Konfigurationsspeicher - ✅
GSDConfig,GSDConfigItem,GSDConfigValue,GSDConfigOptionalValue,GSDConfigCollection- Deklaration der Felder für den ConfigStore - ✅
GSDConfigMemoryValueStore,GSDConfigMemorySecretStore,GSDConfigInProcessLock- Backends für Tests - ✅
GSDLocalStorageManager- Plattformübergreifender Storage-Manager - ✅
GSDUriManager- Browser-URI-Manipulation - ✅
DOCUframeUploadManager- Upload-Funktionalität mit Fortschrittsverfolgung - ✅
GSDBaseConfig- Abstrakte Basis für eigene Konfigurationsklassen - ✅
GSDUploadFile- Datei-Repräsentation mit Metadaten - ❌
_GSDWebConfigManager- Interne Web-Implementierung (nicht zugänglich) - ❌
_GSDAppConfigManager- Interne Mobile-Implementierung (nicht zugänglich) - ❌
_GSDWebUriManager- Interne Web-URI-Implementierung (nicht zugänglich)
Plattform-Kompatibilität #
| Feature | Web | Mobile | Desktop |
|---|---|---|---|
| Konfigurationsverwaltung | ✅ | ✅ | ✅ |
| LocalStorage | ✅ | ❌ | ❌ |
| Storage-Events | ✅ | ❌ | ❌ |
| URI-Management | ✅ | ❌ | ❌ |
| Web-Benachrichtigungen | ✅ | ❌* | ❌* |
| File-Upload | ✅ | ✅ | ✅ |
| Bildverarbeitung | ✅ | ✅ | ✅ |
| Secure Storage | ❌ | ✅ | ✅ |
⚠️ Fallback-Implementierung verfügbar (eingeschränkte Funktionalität)
Hinweise #
- Automatische Plattformauswahl: Das richtige Storage-System wird automatisch gewählt
- Event-basiert: Alle Änderungen werden über Events kommuniziert
- Type-safe: Vollständige TypeScript-Integration für Web-Plattformen
- Memory-safe: Automatisches Cleanup verhindert Memory-Leaks
- Production-ready: Umfassive Fehlerbehandlung und Logging
- Browser-URI-Manipulation: URI-Änderungen ohne Seitenreload (nur Web)
- Native Browser-Notifications: Verwendung der Browser Notification API (nur Web)
- Browser-Erkennung: Automatische Erkennung von Chrome, Firefox, Edge, Safari
- Dokumentiert: Alle Klassen und Methoden vollständig dokumentiert
URI-Manager Spezifika #
Web-Plattform:
- ✅ Browser History API (
history.replaceState()) - ✅ Document Title API (
document.title) - ✅ JavaScript Interop für native Browser-Integration
- ✅ Live-URL-Updates ohne Seitenreload
Mobile/Desktop-Plattform:
- ❌ Keine Funktionalität
Notification-Helper Spezifika #
Web-Plattform:
- ✅ Native Browser Notification API (
new Notification()) - ✅ Permission Management (
Notification.requestPermission()) - ✅ Browser-Erkennung (Chrome, Firefox, Edge, Safari)
- ✅ Automatisches Schließen nach 5 Sekunden
- ✅ Resource Management und Cleanup
Mobile/Desktop-Plattform:
- ❌ Dummy-Implementierung (UnimplementedError)
- ❌ Für native Platforms sollten plattformspezifische Notification-Plugins verwendet werden
Dieses Paket ermöglicht die professionelle Utility-Verwaltung in Ihrer Flutter-Anwendung und bietet umfassende Funktionen für Konfiguration, Storage, File-Upload und Enterprise-Integration bei gleichzeitig sauberer und plattformübergreifender API.