From 85615d253ccda7129fb06a7b690f5e79ac4c3b65 Mon Sep 17 00:00:00 2001 From: Dustin Date: Thu, 6 Aug 2026 18:17:25 +0200 Subject: [PATCH] =?UTF-8?q?v2.55.3=20=E2=80=94=20Code-Review-Fixes:=20fore?= =?UTF-8?q?groundServiceType=20(Android=2014+),=20POST=5FNOTIFICATIONS-Che?= =?UTF-8?q?ck,=20FG-Service-Notification-Channel,=20try/catch=20=5FzeigeSy?= =?UTF-8?q?ncNotification?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CRITICAL: - AndroidManifest: foregroundServiceType="dataSync" für BackgroundService (Android 14+ MissingForegroundServiceTypeException) - main.dart: notificationChannelId + initialNotificationTitle + foregroundServiceTypes für FlutterBackgroundService (fehlende FG-Notification → ANR/crash nach 5s) MEDIUM: - sync_service.dart: POST_NOTIFICATIONS-Permission-Check vor _starteForegroundService (Android 13+) - sync_service.dart: try/catch um _zeigeSyncNotification (plugin-dispose-Sicherheit) flutter analyze: clean | flutter test: 194/194 passed --- android/app/src/main/AndroidManifest.xml | 7 +++++ lib/main.dart | 21 ++++++++++++++ lib/services/sync_service.dart | 36 ++++++++++++++++-------- 3 files changed, 53 insertions(+), 11 deletions(-) diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 7208d24..814a6b1 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -36,6 +36,13 @@ + + + () + ?.createNotificationChannel(fgChannel); + await FlutterBackgroundService().configure( iosConfiguration: IosConfiguration(), androidConfiguration: AndroidConfiguration( onStart: _onServiceStart, autoStart: false, isForegroundMode: true, + notificationChannelId: 'de.baka.melo.fg_service', + initialNotificationTitle: 'Melo Sync', + initialNotificationContent: 'Synchronisiere Musik…', + foregroundServiceTypes: [AndroidForegroundType.dataSync], ), ); diff --git a/lib/services/sync_service.dart b/lib/services/sync_service.dart index 1e5bcb9..cb955c8 100644 --- a/lib/services/sync_service.dart +++ b/lib/services/sync_service.dart @@ -4,6 +4,7 @@ import 'package:flutter/foundation.dart'; import 'package:path_provider/path_provider.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:flutter_local_notifications/flutter_local_notifications.dart'; +import 'package:permission_handler/permission_handler.dart'; import 'package:flutter_background_service/flutter_background_service.dart'; import '../database/db_helper.dart'; import '../models/song.dart'; @@ -577,18 +578,22 @@ class SyncService { if (!Platform.isAndroid) return; final maxP = gesamt > 0 ? gesamt : 1; final p = aktuell > maxP ? maxP : aktuell; - notificationsPlugin.show( - id: _syncNotifyId, - title: 'Synchronisiere…', - body: gesamt > 0 ? '$aktuell / $gesamt Songs' : body, - notificationDetails: NotificationDetails( - android: syncNotificationDetails( - ongoing: true, - progress: p, - maxProgress: maxP, + try { + notificationsPlugin.show( + id: _syncNotifyId, + title: 'Synchronisiere…', + body: gesamt > 0 ? '$aktuell / $gesamt Songs' : body, + notificationDetails: NotificationDetails( + android: syncNotificationDetails( + ongoing: true, + progress: p, + maxProgress: maxP, + ), ), - ), - ); + ); + } catch (_) { + // Plugin kann beim App-Exit bereits disposed sein + } } /// Abschluss-Notification — tippbar (öffnet den Cloud-Tab, payload @@ -630,9 +635,18 @@ class SyncService { /// Startet den Foreground-Service, damit der Sync auch bei Display-aus /// und minimierter App weiterläuft (Android-Prozess-Garantie). + /// v2.55.3: Prüft POST_NOTIFICATIONS-Permission (Android 13+). + /// Ohne diese Permission crasht der Foreground-Service innerhalb von + /// 5 Sekunden (Android killt Services ohne sichtbare Notification). Future _starteForegroundService() async { if (!Platform.isAndroid) return; try { + // Android 13+: Benachrichtigungs-Berechtigung erforderlich + final status = await Permission.notification.status; + if (status.isDenied || status.isPermanentlyDenied) { + MeloLogger().aktion('foreground_sync_skip', {'grund': 'notification_denied'}); + return; + } final svc = FlutterBackgroundService(); final laeuft = await svc.isRunning(); if (!laeuft) {