如何播放音频,当我的Flutter应用终止时(警报应用程序)

问题描述 投票:0回答:1

我正在使用flutter创建的警报应用程序。我正在使用android_alarm_manager_plus,flutter_foreground_task,flutter_local_notifications作为实现警报核心功能的主要软件包。我基本上正在构建警报应用程序,以在特定时间触发选定的日子触发警报。

当应用在前景中还活着时,该应用程序可以通过显示通知并播放警报声来发射警报。但是,当我终止我的应用程序时,设置了警报;它将显示通知。但是没有播放警报。

我是我的PubSpec.yaml包

输入图像描述在此处(单击此链接以查看图像)

当警报发出时,执行了“ AlarmCallback”。在其中,我试图启动循环播放音频的前景服务。每当用户点击“停止警报”通知按钮时,我都会停止音频并关闭前景服务。 我试图向Google搜索这个问题,那里没有太大帮助。因此,请帮助我解决此问题。 这是“ AlarmCallback”,“ ForegroundService”和“ ForegroundServiceHandler”的代码。

alarmcallback

foregroundStartServiceCallback

代码(顶级功能)

@pragma('vm:entry-point') void startForegroundTaskCallback() { FlutterForegroundTask.setTaskHandler(ForegroundServiceHandler()); } @pragma('vm:entry-point') void alarmCallback(int id, Map<String, dynamic> params) async { debugPrint("The alarm callback is running !"); bool isRunningService = await FlutterForegroundTask.isRunningService; debugPrint("The foreground service is running : $isRunningService"); if (!isRunningService) { debugPrint("Init foreground task"); ForegroundTaskService.init(); } else { debugPrint("restart foreground task"); await FlutterForegroundTask.restartService(); } try { var map = params['params'] as Map<String, dynamic>; var alarmModel = Alarmsmodel.fromMap(map); debugPrint(alarmModel.toString()); assert(alarmModel.audioPath != null, " Cannot play audio because ,audio path is null !"); ForegroundTaskService.saveData("audioPath", alarmModel.audioPath); ServiceRequestResult serviceResult = await ForegroundTaskService.startService(); if (serviceResult is ServiceRequestSuccess) { debugPrint("service result is success !"); } else if (serviceResult is ServiceRequestFailure) { debugPrint("service result is faliure !"); } var weekDay = DateTime.now().weekday; // logic to reschedule alarm in repetition pattern. // await LocalAlarmService.rescheduleAlarm(alarmModel, weekDay); } catch (e) { debugPrint("Error : $e"); throw Exception("Something went wrong, after triggering alarmCallback"); } } 这是管理flutter的前景服务班的前景服务班 @pragma('vm:entry-point') void startForegroundTaskCallback() { FlutterForegroundTask.setTaskHandler(ForegroundServiceHandler()); } @pragma('vm:entry-point') void alarmCallback(int id, Map<String, dynamic> params) async { debugPrint("The alarm callback is running !"); bool isRunningService = await FlutterForegroundTask.isRunningService; debugPrint("The foreground service is running : $isRunningService"); if (!isRunningService) { debugPrint("Init foreground task"); ForegroundTaskService.init(); } else { debugPrint("restart foreground task"); await FlutterForegroundTask.restartService(); } try { var map = params['params'] as Map<String, dynamic>; var alarmModel = Alarmsmodel.fromMap(map); debugPrint(alarmModel.toString()); assert(alarmModel.audioPath != null, " Cannot play audio because ,audio path is null !"); ForegroundTaskService.saveData("audioPath", alarmModel.audioPath); ServiceRequestResult serviceResult = await ForegroundTaskService.startService(); if (serviceResult is ServiceRequestSuccess) { debugPrint("service result is success !"); } else if (serviceResult is ServiceRequestFailure) { debugPrint("service result is faliure !"); } var weekDay = DateTime.now().weekday; // logic to reschedule alarm in repetition pattern. // await LocalAlarmService.rescheduleAlarm(alarmModel, weekDay); } catch (e) { debugPrint("Error : $e"); throw Exception("Something went wrong, after triggering alarmCallback"); } }

the the the the theForegroundServiceHandler
的代码

class ForegroundServiceHandler extends TaskHandler { @override Future<void> onStart(DateTime timestamp, TaskStarter starter) async { debugPrint("Fetching audio path."); String? audioPath = await FlutterForegroundTask.getData<String>(key: 'audioPath'); debugPrint("The audio path is $audioPath"); if (audioPath != null && audioPath.isNotEmpty) { debugPrint( "The audio path is not null neither its empty . Audiopath is $audioPath"); AudioService.instance.playAudioInForeground(audioPath); } else { debugPrint( "Error : audioPath is missing. (ForegroundServiceHandler)(onStart)"); } } @override void onNotificationButtonPressed(String id) { super.onNotificationButtonPressed(id); debugPrint("onNotificationButtonPressed"); if (id == "stop_audio") { AudioService.instance.stopAudio(); } FlutterForegroundTask.stopService(); } @override void onNotificationPressed() { super.onNotificationPressed(); debugPrint("onNotificationPressed"); } @override void onNotificationDismissed() { super.onNotificationDismissed(); debugPrint("onNotificationDismissed"); FlutterForegroundTask.stopService(); } @override void onReceiveData(Object data) { super.onReceiveData(data); debugPrint("onReceiveData"); } @override void onRepeatEvent(DateTime timestamp) {} @override Future<void> onDestroy(DateTime timestamp) async { debugPrint("onDestroy invoked. Stopping service"); } }

这是我的代码
audio服务

class AudioService { AudioPlayer? _audioPlayer; bool isAudioPlaying = false; static final AudioService instance = AudioService._internal(); factory AudioService() { return instance; } AudioService._internal() { _audioPlayer = AudioPlayer(); _audioPlayer?.setReleaseMode(ReleaseMode.loop); _audioPlayer?.onPlayerStateChanged.listen((PlayerState state) { isAudioPlaying = (state == PlayerState.playing); }); } void disposeAudio() { _audioPlayer?.dispose(); _audioPlayer = null; } void playAudio(String path) async { if (_audioPlayer == null) { debugPrint("Audio player instance is null !"); } else { debugPrint("Audio Player instance is not null !"); } _audioPlayer ??= AudioPlayer(); //ensure its initialized. if (isAudioPlaying) { await _audioPlayer?.stop(); } debugPrint("Playing audio for audiopath : $path"); await _audioPlayer?.play( AssetSource(path), volume: 1, ); } void stopAudio() async { _audioPlayer ??= AudioPlayer(); debugPrint("Stopping audio instance hashcode : ${_audioPlayer.hashCode}"); await _audioPlayer!.stop(); } void playAudioInForeground(String path) async { String localPath = await getLocalFilePath(path); debugPrint("Setting audio source url"); debugPrint("playing deviceFilePath ."); await _audioPlayer?.play(DeviceFileSource(localPath), volume: 1); } Future<String> getLocalFilePath(String assetPath) async { // Get the app's document directory. final directory = await getApplicationDocumentsDirectory(); final filePath = '${directory.path}/$assetPath'; debugPrint("File path is $filePath"); final file = File(filePath); bool isFilePresent = await file.exists(); debugPrint("Does file exists $isFilePresent"); if (!file.existsSync()) { // load assets as bytes. debugPrint("loading bytes from rootbundle"); ByteData data = await rootBundle.load("assets/$assetPath"); debugPrint("loading bytes from ByteData"); List<int> bytes = data.buffer.asUint8List(); debugPrint("The bytes length is ${bytes.length}"); await file.create(recursive: true); await file.writeAsBytes(bytes); debugPrint("written to file"); } debugPrint("returning device file path - $filePath"); return filePath; } }

	

看起来,当应用程序终止时,您的警报通知正在工作,但是警报音频没有播放。主要问题可能与Android中的背景执行限制有关。以下是一些可能的原因和解决方案: 修改AlarmCallback,如果应用程序未运行,请明确重新启动前景服务: @pragma('vm:entry-point') void alarmCallback(int id, Map<String, dynamic> params) async { debugPrint("The alarm callback is running !"); // Ensure the Foreground Task is Running bool isRunningService = await FlutterForegroundTask.isRunningService; if (!isRunningService) { debugPrint("Starting foreground service..."); ForegroundTaskService.init(); await Future.delayed(Duration(seconds: 2)); // Small delay to ensure service starts } debugPrint("Restarting foreground service..."); await FlutterForegroundTask.restartService(); try { var map = params['params'] as Map<String, dynamic>; var alarmModel = Alarmsmodel.fromMap(map); assert(alarmModel.audioPath != null, "Cannot play audio - Path is null!"); // Save audio path to ForegroundTask ForegroundTaskService.saveData("audioPath", alarmModel.audioPath); ServiceRequestResult serviceResult = await ForegroundTaskService.startService(); if (serviceResult is ServiceRequestSuccess) { debugPrint("Foreground service started successfully!"); } else { debugPrint("Failed to start foreground service."); } } catch (e) { debugPrint("Error in alarmCallback: $e"); } }

确保音频播放正确始于Onstart内部:
flutter foreground-service flutter-audioplayers
1个回答
0
投票

更改文件路径的处理方式,以确保正确加载警报音频文件。

class AudioService { AudioPlayer? _audioPlayer; static final AudioService instance = AudioService._internal(); factory AudioService() { return instance; } AudioService._internal() { _audioPlayer = AudioPlayer(); _audioPlayer?.setReleaseMode(ReleaseMode.loop); } Future<void> playAudioInForeground(String path) async { String localPath = await getLocalFilePath(path); debugPrint("Playing audio from local path: $localPath"); try { await _audioPlayer?.setSource(DeviceFileSource(localPath)); await _audioPlayer?.setVolume(1.0); await _audioPlayer?.play(DeviceFileSource(localPath)); } catch (e) { debugPrint("Error playing audio: $e"); } } Future<String> getLocalFilePath(String assetPath) async { final directory = await getApplicationDocumentsDirectory(); final filePath = '${directory.path}/$assetPath'; final file = File(filePath); if (!file.existsSync()) { ByteData data = await rootBundle.load("assets/$assetPath"); List<int> bytes = data.buffer.asUint8List(); await file.create(recursive: true); await file.writeAsBytes(bytes); } return filePath; } void stopAudio() async { await _audioPlayer?.stop(); } }
AndroidManifest.xml in android/app/src/main/main/androidManifest.xml中的Addd前景服务权限,添加:

<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/> <uses-permission android:name="android.permission.WAKE_LOCK"/>

declare前景服务在androidmanifest.xml内部...,添加:

<service android:name="com.example.alarm.ForegroundService" android:foregroundServiceType="mediaPlayback" android:permission="android.permission.FOREGROUND_SERVICE"/>

屏蔽用户将应用程序添加到主屏幕中:

import 'package:device_info_plus/device_info_plus.dart'; import 'package:battery_optimization/battery_optimization.dart'; void requestBatteryOptimizationPermission() async { bool isIgnoring = await BatteryOptimization.isIgnoringBatteryOptimizations(); if (!isIgnoring) { await BatteryOptimization.openBatteryOptimizationSettings(); } }

call requestBatteryOptimizationpermission()应用程序启动

void main() { WidgetsFlutterBinding.ensureInitialized(); requestBatteryOptimizationPermission(); runApp(MyApp()); }

	

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.