v2.41 — Issue #3: Musik-Download im Hintergrund (flutter_background_service)
- flutter_background_service ^5.0.0 hinzugefügt - AndroidManifest: FOREGROUND_SERVICE_DATA_SYNC Permission - main.dart: Background Service mit configure() initialisiert - _onServiceStart(): Service-Callback für Foreground-Garantie - DownloadService._startBackgroundService(): Foreground Service vor Download - DownloadService._stopBackgroundService(): Stopp nach Batch/Single - Integration in _resetStatus, downloadBatch, downloadVonUrl
This commit is contained in:
@@ -2,6 +2,7 @@
|
|||||||
<uses-permission android:name="android.permission.INTERNET"/>
|
<uses-permission android:name="android.permission.INTERNET"/>
|
||||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
|
||||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK"/>
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK"/>
|
||||||
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC"/>
|
||||||
<uses-permission android:name="android.permission.WAKE_LOCK"/>
|
<uses-permission android:name="android.permission.WAKE_LOCK"/>
|
||||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32"/>
|
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32"/>
|
||||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="29"/>
|
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="29"/>
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import 'package:audio_service/audio_service.dart';
|
|||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
import 'package:permission_handler/permission_handler.dart';
|
import 'package:permission_handler/permission_handler.dart';
|
||||||
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
|
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
|
||||||
|
import 'package:flutter_background_service/flutter_background_service.dart';
|
||||||
import 'database/db_helper.dart';
|
import 'database/db_helper.dart';
|
||||||
import 'services/favoriten_service.dart';
|
import 'services/favoriten_service.dart';
|
||||||
import 'services/auth_service.dart';
|
import 'services/auth_service.dart';
|
||||||
@@ -47,6 +48,16 @@ void main() async {
|
|||||||
AndroidFlutterLocalNotificationsPlugin>()
|
AndroidFlutterLocalNotificationsPlugin>()
|
||||||
?.createNotificationChannel(downloadChannel);
|
?.createNotificationChannel(downloadChannel);
|
||||||
|
|
||||||
|
// ── Background Service initialisieren (Issue #3) ──
|
||||||
|
await FlutterBackgroundService().configure(
|
||||||
|
iosConfiguration: IosConfiguration(),
|
||||||
|
androidConfiguration: AndroidConfiguration(
|
||||||
|
onStart: _onServiceStart,
|
||||||
|
autoStart: false,
|
||||||
|
isForegroundMode: true,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await DbHelper().db;
|
await DbHelper().db;
|
||||||
await FavoritenService().init();
|
await FavoritenService().init();
|
||||||
@@ -148,6 +159,19 @@ Future<void> _starteAutoSyncFallsNoetig() async {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Background Service Callback – hält App im Vordergrund beim Download (Issue #3)
|
||||||
|
@pragma('vm:entry-point')
|
||||||
|
Future<bool> _onServiceStart(ServiceInstance service) async {
|
||||||
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
|
// Service läuft als Foreground-Service und hält den Prozess am Leben.
|
||||||
|
// Der eigentliche Download läuft im Haupt-Isolate – der Service dient nur
|
||||||
|
// als WakeLock / Foreground-Garantie.
|
||||||
|
service.on('stopService').listen((_) {
|
||||||
|
service.stopSelf();
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
class MeloApp extends StatelessWidget {
|
class MeloApp extends StatelessWidget {
|
||||||
const MeloApp({super.key});
|
const MeloApp({super.key});
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import 'package:flutter/foundation.dart';
|
|||||||
import 'package:http/http.dart' as http;
|
import 'package:http/http.dart' as http;
|
||||||
import 'package:path_provider/path_provider.dart';
|
import 'package:path_provider/path_provider.dart';
|
||||||
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
|
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
|
||||||
|
import 'package:flutter_background_service/flutter_background_service.dart';
|
||||||
import '../models/song.dart';
|
import '../models/song.dart';
|
||||||
import '../database/db_helper.dart';
|
import '../database/db_helper.dart';
|
||||||
import '../utils/audio_validator.dart';
|
import '../utils/audio_validator.dart';
|
||||||
@@ -66,13 +67,46 @@ class DownloadService extends ChangeNotifier {
|
|||||||
_aktuellerTitel = null;
|
_aktuellerTitel = null;
|
||||||
_fehler = null;
|
_fehler = null;
|
||||||
_abbruchCompleter = Completer<void>();
|
_abbruchCompleter = Completer<void>();
|
||||||
|
_startBackgroundService();
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Issue #3: Foreground Service starten – hält App im Hintergrund aktiv
|
||||||
|
void _startBackgroundService() {
|
||||||
|
try {
|
||||||
|
final svc = FlutterBackgroundService();
|
||||||
|
svc.isRunning().then((running) {
|
||||||
|
if (!running) {
|
||||||
|
svc.startService();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
debugPrint('🔵 Background Service gestartet');
|
||||||
|
} catch (e) {
|
||||||
|
debugPrint('Background Service Start fehlgeschlagen: $e');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Issue #3: Foreground Service stoppen
|
||||||
|
void _stopBackgroundService() {
|
||||||
|
try {
|
||||||
|
final svc = FlutterBackgroundService();
|
||||||
|
svc.isRunning().then((running) {
|
||||||
|
if (running) {
|
||||||
|
svc.invoke('stopService');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
debugPrint('🔴 Background Service gestoppt');
|
||||||
|
} catch (e) {
|
||||||
|
debugPrint('Background Service Stop fehlgeschlagen: $e');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Song von YouTube herunterladen
|
/// Song von YouTube herunterladen
|
||||||
Future<Song?> downloadVonUrl(String url) async {
|
Future<Song?> downloadVonUrl(String url) async {
|
||||||
_resetStatus();
|
_resetStatus();
|
||||||
return _downloadEinzeln(url);
|
final result = await _downloadEinzeln(url);
|
||||||
|
if (!_ladt) _stopBackgroundService();
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Mehrere URLs/Playlists nacheinander mit Cooldown
|
/// Mehrere URLs/Playlists nacheinander mit Cooldown
|
||||||
@@ -147,6 +181,7 @@ class DownloadService extends ChangeNotifier {
|
|||||||
}
|
}
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
_completeNotification(erfolgreich, urls.length, abgebrochen: sollAbbrechen);
|
_completeNotification(erfolgreich, urls.length, abgebrochen: sollAbbrechen);
|
||||||
|
_stopBackgroundService();
|
||||||
MeloLogger().zustand('download_batch_ende', {
|
MeloLogger().zustand('download_batch_ende', {
|
||||||
'erfolgreich': erfolgreich,
|
'erfolgreich': erfolgreich,
|
||||||
'gesamt': urls.length,
|
'gesamt': urls.length,
|
||||||
|
|||||||
@@ -150,6 +150,38 @@ packages:
|
|||||||
description: flutter
|
description: flutter
|
||||||
source: sdk
|
source: sdk
|
||||||
version: "0.0.0"
|
version: "0.0.0"
|
||||||
|
flutter_background_service:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: flutter_background_service
|
||||||
|
sha256: "70a1c185b1fa1a44f8f14ecd6c86f6e50366e3562f00b2fa5a54df39b3324d3d"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "5.1.0"
|
||||||
|
flutter_background_service_android:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: flutter_background_service_android
|
||||||
|
sha256: ca0793d4cd19f1e194a130918401a3d0b1076c81236f7273458ae96987944a87
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "6.3.1"
|
||||||
|
flutter_background_service_ios:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: flutter_background_service_ios
|
||||||
|
sha256: "6037ffd45c4d019dab0975c7feb1d31012dd697e25edc05505a4a9b0c7dc9fba"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "5.0.3"
|
||||||
|
flutter_background_service_platform_interface:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: flutter_background_service_platform_interface
|
||||||
|
sha256: ca74aa95789a8304f4d3f57f07ba404faa86bed6e415f83e8edea6ad8b904a41
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "5.1.2"
|
||||||
flutter_cache_manager:
|
flutter_cache_manager:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ dependencies:
|
|||||||
crypto: ^3.0.6
|
crypto: ^3.0.6
|
||||||
flutter_secure_storage: ^10.3.1
|
flutter_secure_storage: ^10.3.1
|
||||||
flutter_local_notifications: ^22.2.0
|
flutter_local_notifications: ^22.2.0
|
||||||
|
flutter_background_service: ^5.1.0
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
|||||||
Reference in New Issue
Block a user