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();
+ }
}
}