From e543286bc505548c94a4d83f39d8b01ffee6fe27 Mon Sep 17 00:00:00 2001 From: DragonSlayer_14 Date: Sat, 3 Jan 2026 14:00:53 +0100 Subject: [PATCH] =?UTF-8?q?Feat:=20Erstellt=20die=20M=C3=B6glichkeit,=20Ta?= =?UTF-8?q?sks=20als=20Hintergrundprozesse=20auszuf=C3=BChren?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../background_task_controller.dart | 59 ++++++++++++++++ lib/Controller/port_controller.dart | 68 +++++++++++++++++++ lib/main.dart | 7 +- 3 files changed, 131 insertions(+), 3 deletions(-) create mode 100644 lib/Controller/background_task_controller.dart create mode 100644 lib/Controller/port_controller.dart diff --git a/lib/Controller/background_task_controller.dart b/lib/Controller/background_task_controller.dart new file mode 100644 index 0000000..062a237 --- /dev/null +++ b/lib/Controller/background_task_controller.dart @@ -0,0 +1,59 @@ +import 'dart:async'; +import 'dart:io'; +import 'dart:isolate'; + +import 'package:flutter/services.dart'; +import 'package:workmanager/workmanager.dart'; + +import '../Tasks/generate_transactions_task.dart'; +import 'port_controller.dart'; + +/// Erstellt Hintergrundtasks und führt diese aus +class BackgroundTaskController { + /// Erstellt eine neue Instanz dieser Klasse + BackgroundTaskController() { + if (Platform.isAndroid) { + unawaited(Workmanager().initialize(callbackDispatcher)); + unawaited( + Workmanager().registerPeriodicTask( + 'generate-transactions', + 'generate_transactions', + frequency: const Duration(minutes: 30), + initialDelay: const Duration(minutes: 1), + ), + ); + } else { + unawaited( + Isolate.run(() async { + sleep(const Duration(minutes: 1)); + + while (true) { + final RootIsolateToken? rootIsolateToken = await PortController() + .getRootIsolateToken(); + + if (rootIsolateToken != null) { + BackgroundIsolateBinaryMessenger.ensureInitialized( + rootIsolateToken, + ); + await GenerateTransactionsTask().execute(); + } + sleep(const Duration(minutes: 30)); + } + }), + ); + } + } +} + +/// Die Funktion wird von Hintergrundtasks ausgerufen, um diese auszuführen +@pragma('vm:entry-point') +void callbackDispatcher() { + Workmanager().executeTask((final task, final inputData) { + switch (task) { + case 'generate_transactions': + return GenerateTransactionsTask().execute(); + } + + return Future.value(true); + }); +} diff --git a/lib/Controller/port_controller.dart b/lib/Controller/port_controller.dart new file mode 100644 index 0000000..db812c2 --- /dev/null +++ b/lib/Controller/port_controller.dart @@ -0,0 +1,68 @@ +import 'dart:async'; +import 'dart:isolate'; +import 'dart:ui'; + +import 'package:flutter/services.dart'; + +/// Ein PortController mit verschiedenen FUnktionen zur KOmmunikations zwischen +/// main und anderen Isolates +class PortController { + /// Gibt eine Instanz dieser Klasse zurück + factory PortController() => _instance; + + PortController._internal() { + if (ServicesBinding.rootIsolateToken != null) { + _registerRootIsolateTokenSender(); + } + } + + static final PortController _instance = PortController._internal(); + + /// Fügt einen Port mit [name] zum NameServer hinzu + void addPort(final SendPort sendPort, final String name) { + IsolateNameServer.registerPortWithName(sendPort, name); + } + + /// Gibt einen Port mit [name] vom NameServer zurück, falls gefunden + SendPort? getPort(final String name) => + IsolateNameServer.lookupPortByName(name); + + /// Gibt das [RootIsolateToken] der main-Isolate zurück + Future getRootIsolateToken() async { + final ReceivePort receivePort = ReceivePort(); + + final SendPort? rootPort = IsolateNameServer.lookupPortByName( + 'root-isolate-token', + ); + + if (rootPort == null) { + receivePort.close(); + return null; + } + + rootPort.send(receivePort.sendPort); + + try { + final dynamic message = await receivePort.first; + + if (message is RootIsolateToken) { + return message; + } + + return null; + } finally { + receivePort.close(); + } + } + + void _registerRootIsolateTokenSender() { + final ReceivePort receivePort = ReceivePort() + ..listen((final value) { + if (value is SendPort) { + value.send(ServicesBinding.rootIsolateToken); + } + }); + + addPort(receivePort.sendPort, 'root-isolate-token'); + } +} diff --git a/lib/main.dart b/lib/main.dart index 2e8265b..2cce952 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:routemaster/routemaster.dart'; +import 'Controller/background_task_controller.dart'; import 'Services/navigation_service.dart'; import 'Services/router_service.dart'; import 'Services/theme_service.dart'; @@ -9,6 +10,8 @@ import 'Services/theme_service.dart'; void main() { WidgetsFlutterBinding.ensureInitialized(); + BackgroundTaskController(); + runApp( MaterialApp.router( routerDelegate: RoutemasterDelegate( @@ -22,9 +25,7 @@ void main() { GlobalWidgetsLocalizations.delegate, GlobalCupertinoLocalizations.delegate, ], - supportedLocales: const [ - Locale('de'), - ], + supportedLocales: const [Locale('de')], title: 'DragonLedger 🐉📒', theme: ThemeService.getLightTheme(),