diff --git a/lib/main.dart b/lib/main.dart index 34ba0f1..6da0efb 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -52,6 +52,15 @@ void main() async { // ⭐ 创建 Handler(AudioService 稍后初始化) _audioHandler = AudioPlayerHandler(); + // ⭐ 注册切歌回调:当歌曲切换时,立即更新通知 + AudioService().setOnSongChanged((song) { + _audioHandler!.updateNotification( + id: song.id, + title: song.title, + artist: song.artist, + ); + }); + runApp( MultiProvider( providers: [ diff --git a/lib/services/audio_player_handler.dart b/lib/services/audio_player_handler.dart index dd32d65..7464b62 100644 --- a/lib/services/audio_player_handler.dart +++ b/lib/services/audio_player_handler.dart @@ -4,81 +4,120 @@ import 'package:flutter/foundation.dart'; import 'package:audio_service/audio_service.dart' as audio_service; import '../audio/player_controller.dart'; import '../audio/playback_state_manager.dart'; -import '../services/audio_service.dart'; // 你自己的业务 AudioService +import '../services/audio_service.dart'; class AudioPlayerHandler extends audio_service.BaseAudioHandler { final PlayerController _player = PlayerController(); final PlaybackStateManager _state = PlaybackStateManager(); + String? _currentId; + String? _currentTitle; + String? _currentArtist; + AudioPlayerHandler() { - // ---- 监听播放状态变化,同步到通知栏 ---- + // ---- 播放状态 ---- _player.playingStream.listen((playing) { _state.updatePlaying(playing); _publishState(); }); + // ---- 进度变化 ---- _player.positionStream.listen((position) { _state.updatePosition(position); - final current = playbackState.value; - playbackState.add(audio_service.PlaybackState( - controls: current.controls, - processingState: current.processingState, - playing: current.playing, - androidCompactActionIndices: current.androidCompactActionIndices, - updateTime: DateTime.now(), - )); + // ⭐ 0.18.19 版本:通过更新 PlaybackState 的 updateTime 来驱动进度刷新 + _publishStateOnly(); }); + // ---- 时长变化 ---- _player.durationStream.listen((duration) { _state.updateDuration(duration); + if (_currentId != null && _currentTitle != null) { + _updateMediaItem( + id: _currentId!, + title: _currentTitle!, + artist: _currentArtist!, + duration: duration, + ); + } _publishState(); }); - - // ⭐ 已删除 completed 监听,交由 AudioService 统一处理 - // _player.completedStream.listen((_) { ... }); } + // ---- 发布完整状态 ---- void _publishState() { playbackState.add(_state.playbackState); } + // ---- 0.18.19 版本:只更新时间戳,驱动系统刷新进度 ---- + void _publishStateOnly() { + final current = playbackState.value; + playbackState.add(audio_service.PlaybackState( + controls: current.controls, + processingState: current.processingState, + playing: current.playing, + androidCompactActionIndices: current.androidCompactActionIndices, + updateTime: DateTime.now(), // ⭐ 关键:更新时间戳,系统会重新读取位置 + )); + } + + // ---- 更新媒体信息 ---- + void _updateMediaItem({ + required String id, + required String title, + required String artist, + Duration? duration, + }) { + _currentId = id; + _currentTitle = title; + _currentArtist = artist; + + debugPrint('📢 [handler] updateMediaItem: $title - $artist'); + + mediaItem.add(audio_service.MediaItem( + id: id, + title: title, + artist: artist, + duration: duration ?? _player.duration, + )); + } + + // ---- 外部接口 ---- void updateNotification({ required String id, required String title, required String artist, }) { - debugPrint('📢 [handler] updateNotification: $title'); - mediaItem.add(audio_service.MediaItem( - id: id, - title: title, - artist: artist, - duration: _player.duration, - )); + _updateMediaItem(id: id, title: title, artist: artist); + _publishState(); } - // ---- 系统控制命令 ---- + // ---- 控制命令 ---- @override Future play() async { debugPrint('▶️ [handler] play() called'); _player.play(); + _publishState(); } @override Future pause() async { debugPrint('⏸️ [handler] pause() called'); _player.pause(); + _publishState(); } @override Future stop() async { debugPrint('⏹️ [handler] stop() called'); _player.stop(); + _publishState(); } @override Future seek(Duration position) async { debugPrint('⏩ [handler] seek() called: $position'); _player.seek(position); + _publishStateOnly(); } @override diff --git a/lib/services/audio_service.dart b/lib/services/audio_service.dart index 3c81af7..ff1c0bc 100644 --- a/lib/services/audio_service.dart +++ b/lib/services/audio_service.dart @@ -51,6 +51,9 @@ class AudioService extends ChangeNotifier { // ⭐ 防重入标志 bool _handlingCompletion = false; + // ⭐ 歌曲切换回调(用于通知 Handler 更新 MediaItem) + void Function(Song)? _onSongChanged; + // ---- Getter(高频字段不走 ChangeNotifier) ---- Song? get currentSong => _currentSong; bool get isPlaying => _isPlaying; @@ -75,6 +78,11 @@ class AudioService extends ChangeNotifier { } } + // ---- 注册歌曲切换回调 ---- + void setOnSongChanged(void Function(Song) callback) { + _onSongChanged = callback; + } + // ---- 切换播放模式 ---- void togglePlayMode() { switch (_playMode) { @@ -138,6 +146,9 @@ class AudioService extends ChangeNotifier { final song = _queue[_currentIndex]; _currentSong = song; + // ⭐ 切歌时触发回调(通知 Handler 更新 MediaItem) + _onSongChanged?.call(song); + // ⭐ 重置进度(用 ValueNotifier) positionNotifier.value = Duration.zero; durationNotifier.value = Duration.zero; @@ -266,7 +277,7 @@ class AudioService extends ChangeNotifier { }), ); - // ⭐ 唯一监听 completed 的地方 + // ⭐ 唯一监听 completed 的地方(带防重入) _subscriptions.add( player.stream.completed.listen((_) { _onPlaybackCompleted(); @@ -282,7 +293,7 @@ class AudioService extends ChangeNotifier { _subscriptions.clear(); } - // ⭐ 防重入 + // ⭐ 防重入的完成事件处理 void _onPlaybackCompleted() { if (_handlingCompletion) { debugPrint('⚠️ [service] completed ignored: already handling'); diff --git a/pubspec.yaml b/pubspec.yaml index 15d7cc8..129637e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -36,7 +36,7 @@ dependencies: provider: ^6.1.2 dio: ^5.4.0 # HTTP 客户端 xml: ^6.5.0 - audio_service: ^0.18.13 + audio_service: 0.18.19 audio_session: ^0.1.21 permission_handler: ^11.3.1 flutter_cache_manager: ^3.3.1