目前状态栏控制大部分已生效,剩余暂停到播放的链路还有问题

This commit is contained in:
2026-08-21 00:03:04 +08:00
parent bb8e4caf48
commit 8ecca4ac01
2 changed files with 118 additions and 40 deletions
+93 -22
View File
@@ -1,4 +1,4 @@
// lib/services/audio_player_handler.dart
import 'package:flutter/material.dart';
import 'package:audio_service/audio_service.dart';
import 'playback_service.dart';
import 'audio_service.dart' as local_audio;
@@ -7,84 +7,155 @@ class AudioPlayerHandler extends BaseAudioHandler {
final PlaybackService _playback = PlaybackService();
late final local_audio.AudioService _localAudio;
MediaItem? _currentMediaItem;
AudioPlayerHandler() {
_localAudio = local_audio.AudioService();
// 1. 监听播放状态(只更新 playing)
_playback.player.stream.playing.listen((playing) {
playbackState.add(playbackState.value.copyWith(
playing: playing,
));
_updatePlaybackState(playing: playing);
_syncMediaItem();
});
// 2. ⭐ 进度更新:跳过,因为当前版本不支持 position 参数
// 通知栏进度条不会动,但播放/暂停/切歌功能正常
// 如果后续需要,可以升级 audio_service 版本或改用其他方案
// 3. 监听播放完成(触发下一首)
_playback.player.stream.completed.listen((_) {
debugPrint('🎵 [handler] playback completed, auto next');
_localAudio.next();
_updatePlaybackState();
_syncMediaItem();
});
// 4. 监听时长变化,更新 MediaItem
_playback.player.stream.duration.listen((duration) {
if (_currentMediaItem != null) {
_currentMediaItem = _currentMediaItem!.copyWith(duration: duration);
mediaItem.add(_currentMediaItem);
final current = mediaItem.value;
if (current != null && current.duration != duration) {
mediaItem.add(current.copyWith(duration: duration));
}
});
}
/// 外部调用更新通知栏
void _syncMediaItem() {
final song = _localAudio.currentSong;
debugPrint(
'🎵 [handler] _syncMediaItem: currentSong = ${song?.title ?? "null"}');
if (song != null) {
mediaItem.add(MediaItem(
id: song.id,
title: song.title,
artist: song.artist,
duration: _playback.player.state.duration,
));
}
}
void updateNotification({
required String id,
required String title,
required String artist,
}) {
_currentMediaItem = MediaItem(
mediaItem.add(MediaItem(
id: id,
title: title,
artist: artist,
duration: _playback.player.state.duration,
);
mediaItem.add(_currentMediaItem);
));
_updatePlaybackState();
}
void _updatePlaybackState({bool? playing}) {
final isPlaying = playing ?? _playback.player.state.playing;
debugPrint('🎵 _updatePlaybackState: isPlaying=$isPlaying');
final controls = [
MediaControl.skipToPrevious,
if (isPlaying) MediaControl.pause else MediaControl.play,
MediaControl.skipToNext,
];
debugPrint('🎵 controls: ${controls.map((c) => c.action).join(', ')}');
playbackState.add(PlaybackState(
controls: controls,
processingState: AudioProcessingState.ready,
playing: isPlaying,
androidCompactActionIndices: const [0, 1, 2],
updateTime: DateTime.now(),
));
}
// ---- AudioHandler 接口实现 ----
@override
Future<void> play() async {
debugPrint('🎵 [audio_service] play() called');
_playback.resume();
_updatePlaybackState(playing: true);
_syncMediaItem();
}
@override
Future<void> pause() async {
debugPrint('🎵 [audio_service] pause() called');
_playback.pause();
_updatePlaybackState(playing: false);
}
@override
Future<void> stop() async {
debugPrint('🎵 [audio_service] stop() called');
_playback.stop();
_updatePlaybackState(playing: false);
}
@override
Future<void> seek(Duration position) async {
debugPrint('🎵 [audio_service] seek() called: $position');
_playback.seek(position);
}
@override
Future<void> skipToNext() async {
debugPrint('🎵 [audio_service] skipToNext() called');
_localAudio.next();
_updatePlaybackState();
_syncMediaItem();
}
@override
Future<void> skipToPrevious() async {
debugPrint('🎵 [audio_service] skipToPrevious() called');
_localAudio.previous();
_updatePlaybackState();
_syncMediaItem();
}
@override
Future<void> click([MediaButton button = MediaButton.media]) async {
// 默认行为:打开 App
debugPrint(
'🎵 [audio_service] click(): ${button.name} (index: ${button.index})');
final name = button.name.toLowerCase();
if (name.contains('play') || name.contains('media')) {
debugPrint('🎵 → play() via click');
await play();
return;
}
if (name.contains('pause')) {
debugPrint('🎵 → pause() via click');
await pause();
return;
}
if (name.contains('next') || name.contains('skip_next')) {
debugPrint('🎵 → skipToNext() via click');
await skipToNext();
return;
}
if (name.contains('previous') || name.contains('skip_previous')) {
debugPrint('🎵 → skipToPrevious() via click');
await skipToPrevious();
return;
}
debugPrint('🎵 → fallback toggle');
if (_playback.player.state.playing) {
await pause();
} else {
await play();
}
}
}