From 8ecca4ac01afe8b36890bf2989545b3c07700f8a Mon Sep 17 00:00:00 2001 From: lxh2875931338 Date: Fri, 21 Aug 2026 00:03:04 +0800 Subject: [PATCH] =?UTF-8?q?=E7=9B=AE=E5=89=8D=E7=8A=B6=E6=80=81=E6=A0=8F?= =?UTF-8?q?=E6=8E=A7=E5=88=B6=E5=A4=A7=E9=83=A8=E5=88=86=E5=B7=B2=E7=94=9F?= =?UTF-8?q?=E6=95=88=EF=BC=8C=E5=89=A9=E4=BD=99=E6=9A=82=E5=81=9C=E5=88=B0?= =?UTF-8?q?=E6=92=AD=E6=94=BE=E7=9A=84=E9=93=BE=E8=B7=AF=E8=BF=98=E6=9C=89?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- android/app/src/main/AndroidManifest.xml | 43 +++++---- lib/services/audio_player_handler.dart | 115 ++++++++++++++++++----- 2 files changed, 118 insertions(+), 40 deletions(-) diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index b45c06c..bfeb3ed 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -1,9 +1,7 @@ - + - - @@ -15,6 +13,7 @@ android:icon="@mipmap/ic_launcher" android:usesCleartextTraffic="true" android:foregroundServiceType="mediaPlayback"> + - + android:resource="@style/NormalTheme" /> - + + + android:exported="true"> + + + + + + + + + + + + + + + - + - + \ No newline at end of file diff --git a/lib/services/audio_player_handler.dart b/lib/services/audio_player_handler.dart index d6a0669..7722957 100644 --- a/lib/services/audio_player_handler.dart +++ b/lib/services/audio_player_handler.dart @@ -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 play() async { + debugPrint('🎵 [audio_service] play() called'); _playback.resume(); + _updatePlaybackState(playing: true); + _syncMediaItem(); } @override Future pause() async { + debugPrint('🎵 [audio_service] pause() called'); _playback.pause(); + _updatePlaybackState(playing: false); } @override Future stop() async { + debugPrint('🎵 [audio_service] stop() called'); _playback.stop(); + _updatePlaybackState(playing: false); } @override Future seek(Duration position) async { + debugPrint('🎵 [audio_service] seek() called: $position'); _playback.seek(position); } @override Future skipToNext() async { + debugPrint('🎵 [audio_service] skipToNext() called'); _localAudio.next(); + _updatePlaybackState(); + _syncMediaItem(); } @override Future skipToPrevious() async { + debugPrint('🎵 [audio_service] skipToPrevious() called'); _localAudio.previous(); + _updatePlaybackState(); + _syncMediaItem(); } @override Future 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(); + } } }