Browse Source

上传音乐服务逻辑代码

weicu
liwei1dao 1 year ago
parent
commit
f0bc407dd4
  1. 4
      lib/core/bindings/initial_binding.dart
  2. 98
      lib/data/services/qq_musoc.dart
  3. 5
      lib/modules/agent/controllers/agent_controller.dart
  4. 4
      lib/modules/agent/views/message_bubble.dart
  5. 84
      lib/modules/agent/views/qqmusic_card.dart
  6. 87
      lib/modules/qqmusic/controllers/qqmusic_playlist_controller.dart
  7. 61
      lib/modules/qqmusic/views/qqmusic_playlist_view.dart
  8. 2
      local_plugins/agent_service/android/build.gradle.kts
  9. 68
      local_plugins/agent_service/android/src/main/kotlin/com/yunqiinnovation/agent_service/AgentService.kt
  10. 66
      local_plugins/chat_api/android/src/main/kotlin/com/yunqiinnovation/chat_api/QQMusicSystemFunctionHandler.kt
  11. 1
      local_plugins/qq_music/android/src/main/kotlin/com/yunqiinnovation/qq_music/QQMusicManager.kt
  12. 65
      local_plugins/qq_music/android/src/main/kotlin/com/yunqiinnovation/qq_music/QqMusicPlugin.kt
  13. 12
      local_plugins/qq_music/lib/qq_music.dart

4
lib/core/bindings/initial_binding.dart

@ -66,9 +66,13 @@ class InitialBinding extends Bindings {
// 会议助手音频上传
Get.lazyPut<UserportraitManager>(() => UserportraitManager(), fenix: true);
// qq音乐服务
Get.lazyPut<QqMusocService>(() => QqMusocService(), fenix: true);
// 强制初始化 qq_music 插件
// Get.find<QqMusocService>().initializePlugin();
// 新手引导
Get.lazyPut<NoviceGuideService>(() => NoviceGuideService(), fenix: true);

98
lib/data/services/qq_musoc.dart

@ -25,11 +25,31 @@ class QqMusocService extends GetxService {
// 监听器列表 - 用于通知页面状态变化
final List<Function()> _listeners = [];
/// 初始化
/// 初始化插件并尝试自动登录
Future<void> initializePlugin() async {
try {
// 先触发插件注册
// await _qqMusic.getPlatformVersion();
// 尝试自动登录
final result = await _qqMusic.login();
if (result['success'] == true) {
print('QQ音乐自动登录成功: ${result['openId']}');
syncCurrentPlayInfo();
} else {
print('QQ音乐自动登录失败: ${result['error']}');
}
} catch (e) {
print('QQ音乐插件初始化失败: $e');
}
}
@override
void onInit() {
super.onInit();
print('🎵 [QQMusicService] 全局音乐服务初始化');
print('QQ音乐 全局音乐服务初始化');
// 立即初始化插件
initializePlugin();
}
@override
@ -71,8 +91,8 @@ class QqMusocService extends GetxService {
// 立即执行一次同步
_syncPlaybackInfo();
// 启动定时器,每秒同步一次
_stateMonitorTimer = Timer.periodic(const Duration(seconds: 1), (timer) {
// 改为每2-3秒同步一次,减少频率
_stateMonitorTimer = Timer.periodic(const Duration(seconds: 2), (timer) {
_syncPlaybackInfo();
});
@ -87,9 +107,19 @@ class QqMusocService extends GetxService {
}
/// 统一同步播放信息
bool _isSyncing = false;
Future<void> _syncPlaybackInfo() async {
if (_isSyncing) {
print('🔄 [QQMusicService] 上次同步未完成,跳过本次');
return;
}
_isSyncing = true;
try {
final result = await _qqMusic.syncCurrentPlayInfo();
final result = await _qqMusic
.syncCurrentPlayInfo()
.timeout(const Duration(milliseconds: 500)); // 500ms超时
if (result['success'] == true && result['data'] != null) {
final data = result['data'];
@ -160,12 +190,22 @@ class QqMusocService extends GetxService {
print('❌ [QQMusicService] 全局同步失败,停止监听');
stopPlaybackStateMonitor();
}
} on TimeoutException {
print('⏰ [QQMusicService] 同步超时,跳过本次更新');
} catch (e) {
print('💥 [QQMusicService] 全局同步异常: $e');
stopPlaybackStateMonitor();
} finally {
_isSyncing = false;
}
}
// 后台执行的同步方法
static Future<Map<String, dynamic>> _performSync(dynamic _) async {
final qqMusic = QqMusic();
return await qqMusic.syncCurrentPlayInfo();
}
/// 格式化时间
String formatDuration(int milliseconds) {
final duration = Duration(milliseconds: milliseconds);
@ -234,7 +274,7 @@ class QqMusocService extends GetxService {
currentPosition.value = 0;
// 启动全局状态监听
print('🎵 [QQMusicService] 开始播放,启动全局状态监听');
print('🎵 [QQMusicService] 开始播放,启动全局状态监听');
startPlaybackStateMonitor();
_notifyListeners();
@ -376,6 +416,52 @@ class QqMusocService extends GetxService {
Future<Map<String, dynamic>> syncCurrentPlayInfo() async {
try {
final result = await _qqMusic.syncCurrentPlayInfo();
// 如果同步成功,更新全局状态
if (result['success'] == true && result['data'] != null) {
final data = result['data'];
// 更新播放状态
final newIsPlaying = data['isPlaying'] ?? false;
if (isPlaying.value != newIsPlaying) {
isPlaying.value = newIsPlaying;
}
// 更新播放时间(Android端返回秒,转换为毫秒)
final currentTimeSec = data['currentTime'] ?? 0;
final totalTimeSec = data['totalTime'] ?? 0;
final newCurrentPosition = (currentTimeSec * 1000).round();
final newTotalDuration = (totalTimeSec * 1000).round();
if (currentPosition.value != newCurrentPosition) {
currentPosition.value = newCurrentPosition;
}
if (totalDuration.value != newTotalDuration) {
totalDuration.value = newTotalDuration;
}
// 更新当前歌曲信息
final songData = data['currentSong'];
if (songData != null) {
final newSong = SongModel(
mid: songData['mid'] ?? '',
name: songData['name'] ?? '',
artist: songData['singer'] ?? '',
album: songData['album'] ?? '',
albumPic: songData['coverUri'],
duration: songData['duration'] ?? 0,
);
if (currentSong.value?.mid != newSong.mid) {
currentSong.value = newSong;
}
}
// 通知所有监听器
_notifyListeners();
}
return result;
} catch (e) {
return {'success': false, 'error': '同步播放信息失败: ${e.toString()}'};

5
lib/modules/agent/controllers/agent_controller.dart

@ -3,6 +3,7 @@ import 'dart:convert';
import 'dart:ffi';
import 'dart:io';
import 'package:amap_service/amap_service.dart';
import 'package:voitrans/data/services/qq_musoc.dart';
import '../../../data/services/novice_guide_service.dart';
import '/core/utils/upload_oss.dart';
import '/data/models/user_Info.dart';
@ -44,7 +45,7 @@ class AgentController extends GetxController {
//音乐播放管理
final _musiceManager = Get.find<MusicManager>();
final _qqmusicManager = Get.find<QqMusocService>();
// 导航管理
final _navigationManager = Get.find<NavigationManager>();
RxBool isPlaying = false.obs;
@ -157,6 +158,8 @@ class AgentController extends GetxController {
_setupTextInputListener(); //设置文本输入监听器
startVoiceInput(); //开启语音输入
_qqmusicManager.syncCurrentPlayInfo();
}
// 初始化音乐播放状态

4
lib/modules/agent/views/message_bubble.dart

@ -251,9 +251,9 @@ class MessageBubble extends GetView<AgentController> {
// return buildMusicContent(context, playlist);
// }
// } else
if (meta!.keys.contains('qqmusic_search_songs')) {
if (meta!.keys.contains('qqmusic_searchandplay_songs')) {
final qqmusic_search_songs =
meta!['qqmusic_search_songs'] as Map<String, dynamic>;
meta!['qqmusic_searchandplay_songs'] as Map<String, dynamic>;
final data = qqmusic_search_songs['data'];
if (data != null && data is List) {
//qq音乐

84
lib/modules/agent/views/qqmusic_card.dart

@ -2,22 +2,26 @@ import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart';
import '../../../routes/app_routes.dart';
import '../controllers/agent_controller.dart';
import '../../../data/services/qq_musoc.dart';
import '../../../data/models/song_model.dart';
import 'circular_progress_button.dart';
/// 构建音乐项目
Widget buildQQMusicItem(
BuildContext context, String id, String name, String singer, String image) {
final controller = Get.find<AgentController>(); // 获取控制器
final qqMusicService = QqMusocService.to; // 使用QQ音乐全局服务
final isDarkMode = Theme.of(context).brightness == Brightness.dark;
Map<String, dynamic> song = {
'id': id,
'title': name,
'artist': singer,
'coverUrl': image,
};
controller.musicStatus(); //刷新状态
// 创建SongModel对象 - 修复字段名
final song = SongModel(
mid: id,
name: name,
artist: singer, // 修复:使用 artist 而不是 singer
album: '', // 添加必需的 album 字段
duration: 0, // 默认时长,实际播放时会更新
albumPic: image, // 修复:使用 albumPic 而不是 pic
);
return Container(
padding: EdgeInsets.all(14.w),
decoration: BoxDecoration(
@ -84,12 +88,16 @@ Widget buildQQMusicItem(
),
),
Obx(() {
final isThisPlaying =
controller.isPlaying.value && controller.currentId.value == id;
// 使用QQ音乐服务的全局状态
final isThisPlaying = qqMusicService.isPlaying.value &&
qqMusicService.currentSong.value?.mid == id;
// 只有当前播放的歌曲才显示进度
// 计算播放进度
final currentProgress =
isThisPlaying ? controller.progress.value : 0.0;
isThisPlaying && qqMusicService.totalDuration.value > 0
? qqMusicService.currentPosition.value /
qqMusicService.totalDuration.value
: 0.0;
return CircularProgressButton(
isPlaying: isThisPlaying,
@ -100,33 +108,43 @@ Widget buildQQMusicItem(
strokeWidth: 2.0,
onPlayPause: () async {
try {
if (controller.isPlaying.value) {
if (controller.currentId.value == id) {
if (qqMusicService.isPlaying.value) {
if (qqMusicService.currentSong.value?.mid == id) {
// 当前歌曲正在播放,暂停它
await controller.musicPause();
await qqMusicService.pauseMusic();
} else {
// 其他歌曲正在播放,播放这首歌
await controller.musicPlay(song);
await qqMusicService.playSongs(
songMids: [id],
index: 0,
songList: [song],
currentSongModel: song,
);
}
} else {
if (controller.currentId.value == id) {
if (qqMusicService.currentSong.value?.mid == id) {
// 当前歌曲已暂停,恢复播放
await controller.musicResume();
await qqMusicService.resumeMusic();
} else {
// 播放新歌曲
await controller.musicPlay(song);
await qqMusicService.playSongs(
songMids: [id],
index: 0,
songList: [song],
currentSongModel: song,
);
}
}
} catch (e) {
// 静默处理错误,避免影响用户体验
print('播放控制失败: $e');
}
},
onSeek: isThisPlaying
? (seekProgress) {
// 只有当前播放的歌曲才允许跳转
final targetPosition =
(controller.duration.value * seekProgress).round();
controller.seekToPosition(targetPosition);
// QQ音乐暂不支持拖拽进度,可以在这里添加相关逻辑
// 或者显示提示信息
print('QQ音乐暂不支持拖拽进度');
}
: null,
);
@ -140,8 +158,20 @@ Widget buildQQMusicItem(
Widget buildQQMusicContent(
BuildContext context, List<Map<String, dynamic>> playlist) {
final isDarkMode = Theme.of(context).brightness == Brightness.dark;
final controller = Get.find<AgentController>(); // 获取控制器
controller.updateCurrentPlaylistContext(playlist, controller.currentId.value);
final qqMusicService = QqMusocService.to; // 使用QQ音乐全局服务
// 将播放列表转换为SongModel列表 - 修复字段名
final songList = playlist
.map((item) => SongModel(
mid: item["mid"] ?? "",
name: item["name"] ?? "未知歌曲",
artist: item["singer"] ?? "未知歌手", // 修复:使用 artist 而不是 singer
album: '', // 添加必需的 album 字段
duration: 0,
albumPic: item["pic"] ?? "", // 修复:使用 albumPic 而不是 pic
))
.toList();
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@ -209,7 +239,7 @@ Widget buildQQMusicContent(
child: TextButton(
onPressed: () {
// 跳转到完整歌单页面,传递完整的歌单数据
Get.toNamed(Routes.qqmusic, arguments: playlist);
Get.toNamed(Routes.qqmusic, arguments: {"playlist": playlist});
},
style: TextButton.styleFrom(
minimumSize: Size.zero,

87
lib/modules/qqmusic/controllers/qqmusic_playlist_controller.dart

@ -1,6 +1,7 @@
import 'package:get/get.dart';
import '../../../data/models/song_model.dart';
import '../../../data/services/qq_musoc.dart';
import '../../../core/utils/logger.dart';
class QQMusicPlaylistController extends GetxController {
final QqMusocService _qqMusicService = QqMusocService.to;
@ -25,22 +26,83 @@ class QQMusicPlaylistController extends GetxController {
final arguments = Get.arguments;
if (arguments != null && arguments['playlist'] != null) {
final List<dynamic> playlistData = arguments['playlist'];
final songList =
playlistData.map((item) => SongModel.fromJson(item)).toList();
try {
// 解析播放列表数据
final songList = playlistData
.map((item) {
try {
return SongModel.fromJson(item);
} catch (e) {
Logger.e('QQMusicPlaylist', '解析歌曲数据失败: $e, 数据: $item');
return null;
}
})
.where((song) => song != null)
.cast<SongModel>()
.toList();
Logger.d('QQMusicPlaylist', '成功解析歌曲数量: ${songList.length}');
// 更新播放列表
_qqMusicService.playlist.assignAll(songList);
// 安全地设置当前歌曲
if (songList.isNotEmpty) {
_qqMusicService.currentSong.value = songList.first;
_qqMusicService.currentIndex.value = 0;
Logger.d('QQMusicPlaylist', '设置当前歌曲: ${songList.first.name}');
} else {
_qqMusicService.currentSong.value = null;
_qqMusicService.currentIndex.value = 0;
Logger.w('QQMusicPlaylist', '播放列表为空,无法设置当前歌曲');
}
} catch (e) {
Logger.e('QQMusicPlaylist', '处理播放列表时发生异常: $e');
// 确保状态一致性
_qqMusicService.currentSong.value = null;
_qqMusicService.currentIndex.value = 0;
}
} else {
Logger.w('QQMusicPlaylist', '未接收到播放列表参数');
}
// 确保 playlist 初始化
if (_qqMusicService.playlist.isEmpty) {
Logger.w('QQMusicPlaylist', 'Playlist is empty on init');
}
// 添加状态监听器
_qqMusicService.addListener(_onMusicStateChanged);
// 界面初始化时同步播放状态和进度
_syncInitialState();
print('🎵 [QQMusicPlaylistController] 控制器初始化完成');
}
/// 同步初始播放状态
Future<void> _syncInitialState() async {
try {
Logger.d('QQMusicPlaylist', '开始同步初始播放状态');
// 同步当前播放信息
await _qqMusicService.syncCurrentPlayInfo();
// 如果当前有音乐在播放,启动状态监听
if (_qqMusicService.isPlaying.value) {
Logger.d('QQMusicPlaylist', '检测到音乐正在播放,启动状态监听');
_qqMusicService.startPlaybackStateMonitor();
}
// 触发UI更新
update();
Logger.d('QQMusicPlaylist', '初始状态同步完成');
} catch (e) {
Logger.e('QQMusicPlaylist', '初始状态同步失败: $e');
}
}
@override
void onClose() {
// 移除状态监听器
@ -57,10 +119,29 @@ class QQMusicPlaylistController extends GetxController {
/// 播放歌曲
Future<void> playSong(SongModel song, {List<SongModel>? songList}) async {
try {
final List<SongModel> finalSongList = songList ?? [song];
// 如果没有传入歌曲列表,使用当前播放列表
final List<SongModel> finalSongList = songList ?? playlist.toList();
final songMids = finalSongList.map((s) => s.mid).toList();
final playIndex = finalSongList.indexOf(song);
// 如果歌曲不在当前列表中,则只播放这一首
if (playIndex == -1) {
final singleSongList = [song];
final result = await _qqMusicService.playSongs(
songMids: [song.mid],
index: 0,
songList: singleSongList,
currentSongModel: song,
);
if (result['success'] == true) {
Get.snackbar('开始播放', song.name);
} else {
Get.snackbar('播放失败', result['error'] ?? '未知错误');
}
return;
}
final result = await _qqMusicService.playSongs(
songMids: songMids,
index: playIndex,

61
lib/modules/qqmusic/views/qqmusic_playlist_view.dart

@ -26,7 +26,7 @@ class QqmusicPlaylistView extends GetView<QQMusicPlaylistController> {
elevation: 0,
),
backgroundColor: isDarkMode ? Colors.black : Colors.grey[50],
body: controller.playlist.isEmpty
body: controller.playlist.isEmpty || controller.currentSong.value == null
? Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
@ -70,21 +70,43 @@ class QqmusicPlaylistView extends GetView<QQMusicPlaylistController> {
// 构建当前播放音乐详情部分
Widget _buildCurrentPlayingSection(bool isDarkMode) {
return SingleChildScrollView(
// 添加滚动支持
child: Obx(() {
// 添加空值检查
final currentSong = controller.currentSong.value;
if (currentSong == null) {
return Container(
padding: EdgeInsets.symmetric(horizontal: 20.w, vertical: 12.h),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// 封面图片 - 响应式尺寸
_buildCoverImage(controller.currentSong.value!.albumPic ?? '',
isDarkMode, // Handle nullable albumPic
size: 110.w),
Icon(
Icons.music_note,
size: 110.w,
color: Colors.grey[400],
),
SizedBox(height: 12.h),
// 歌曲信息
_buildSongInfo(controller.currentSong.value!.name,
controller.currentSong.value!.artist, isDarkMode),
Text(
'暂无播放音乐',
style: TextStyle(
fontSize: 16.sp,
color: Colors.grey[600],
),
),
],
),
);
}
return Container(
padding: EdgeInsets.symmetric(horizontal: 20.w, vertical: 12.h),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// 封面图片 - 现在安全了
_buildCoverImage(currentSong.albumPic ?? '', isDarkMode, size: 110.w),
SizedBox(height: 12.h),
// 歌曲信息 - 现在安全了
_buildSongInfo(currentSong.name, currentSong.artist, isDarkMode),
SizedBox(height: 16.h),
// 进度条
_buildProgressBar(isDarkMode),
@ -133,15 +155,15 @@ class QqmusicPlaylistView extends GetView<QQMusicPlaylistController> {
// 构建歌单列表部分
Widget _buildPlaylistSection(bool isDarkMode) {
return GetBuilder<QQMusicPlaylistController>(
builder: (controller) {
return ListView.builder(
padding: EdgeInsets.symmetric(horizontal: 20.w, vertical: 8.h),
itemCount: controller.playlist.length,
itemBuilder: (context, index) {
final song = controller.playlist[index];
return _buildMusicItem(
context,
song,
isDarkMode,
return _buildMusicItem(context, song, isDarkMode);
},
);
},
);
@ -236,9 +258,10 @@ class QqmusicPlaylistView extends GetView<QQMusicPlaylistController> {
SizedBox(width: 14.w),
// 播放按钮
Obx(() {
final currentIdInt = song.mid;
// 使用 currentSong 的 mid 来判断是否是当前播放的歌曲
final isThisPlaying = controller.isPlaying.value &&
controller.currentIndex.value == currentIdInt;
controller.currentSong.value?.mid == song.mid;
final currentProgress = isThisPlaying
? controller.totalDuration.value > 0
? controller.currentPosition.value /
@ -257,9 +280,9 @@ class QqmusicPlaylistView extends GetView<QQMusicPlaylistController> {
Logger.d('MusicPlaylistView',
'播放按钮被点击,当前播放状态: ${controller.isPlaying.value}');
Logger.d('MusicPlaylistView',
'当前歌曲ID: ${controller.currentIndex.value}, 点击歌曲ID: $currentIdInt');
'当前歌曲ID: ${controller.currentSong.value?.mid}, 点击歌曲ID: ${song.mid}');
if (controller.isPlaying.value) {
if (controller.currentIndex.value == currentIdInt) {
if (controller.currentSong.value?.mid == song.mid) {
Logger.d('MusicPlaylistView', '暂停当前播放的歌曲');
await controller.togglePlayPause();
} else {
@ -513,7 +536,9 @@ class QqmusicPlaylistView extends GetView<QQMusicPlaylistController> {
mainAxisAlignment: MainAxisAlignment.center,
children: [
IconButton(
onPressed: () {},
onPressed: () async {
await controller.previousSong();
},
iconSize: 32.w,
padding: EdgeInsets.all(8.w), // 增大触摸区域
icon: Icon(

2
local_plugins/agent_service/android/build.gradle.kts

@ -53,4 +53,6 @@ dependencies {
add("compileOnly", project(":location_service"))
add("compileOnly", project(":bytedance_speech"))
add("compileOnly", project(":user_portrait"))
add("compileOnly", project(":qq_music"))
}

68
local_plugins/agent_service/android/src/main/kotlin/com/yunqiinnovation/agent_service/AgentService.kt

@ -13,6 +13,7 @@ import com.yunqiinnovation.music_service.MusicServiceStarter
import com.yunqiinnovation.amap_service.NavigationServiceHelper
import com.yunqiinnovation.user_portrait.UserPortrait
import com.yunqiinnovation.location_service.LocationService
import com.yunqiinnovation.qq_music.QQMusicSingleton
import android.util.Log
import kotlinx.coroutines.*
import java.util.Collections
@ -1673,7 +1674,40 @@ object AgentService : CoroutineScope {
} else {
Log.w(TAG, "card_musiclist.musics 不是一个数组")
}
} else if (meta.has("card_navigation")) { //导航服务
} else if (toolname == "qqmusic_searchandplay_songs" && meta.has("data")) { //qq音乐
//"{\"mid\": \"$mid\", \"name\": \"$name\", \"artist\": \"$artist\", \"album\": \"$album\", \"duration\":$duration,\"pic\": \"$pic\"}"
val musics = meta.optJSONArray("data")
if (musics != null) {
val playlist = mutableListOf<Map<String, Any>>()
for (i in 0 until musics.length()) {
val item = musics.optJSONObject(i) ?: continue
val mid = item.optString("mid", "")
val name = item.optString("name", "")
val artist = item.optString("artist", "")
val album = item.optString("album", "")
val duration = item.optInt("duration", 0)
val pic = item.optLong("pic", 0)
playlist.add(
mapOf(
"mid" to mid,
"name" to name,
"artist" to artist,
"album" to album,
"duration" to duration,
"pic" to pic
)
)
}
if (playlist.isNotEmpty()) {
processQQMusicPlayList(playlist)
} else {
Log.w(TAG, "qqmusic_searchandplay_songs 中没有有效的音乐条目")
}
} else {
Log.w(TAG, "qqmusic_searchandplay_songs.musics 不是一个数组")
}
}else if (meta.has("card_navigation")) { //导航服务
val cardNavigation = meta.getJSONObject("card_navigation")
val start = cardNavigation.optString("start", "")
val end = cardNavigation.optString("end", "")
@ -1725,7 +1759,39 @@ object AgentService : CoroutineScope {
Log.e(TAG, "音乐列表为空,未启动播放服务")
}
}
/**
* 处理音乐播放列表
* 将ai返回的音乐连接 在后台启动播放
*
* @param musicUrl 图片文件路径
* @param name 歌曲名称,默认为空
* @param singer 歌手,默认为false
* @return 是否成功开始处理
*/
fun processQQMusicPlayList(songs: List<Map<String, Any>>) {
// 如果 playlist 中有有效的歌曲,开始播放
if (songs.isNotEmpty()) {
val qqMusicSingleton = QQMusicSingleton.getInstance()
// 从songs中提取mid字段构建songMids列表
val songMids = songs.mapNotNull { song ->
song["mid"] as? String
}.filter { it.isNotEmpty() }
if (songMids.isNotEmpty()) {
qqMusicSingleton.playSongs(songMids, 0) { result ->
result.onSuccess {
Log.i(TAG, "QQ音乐播放列表启动成功,共${songMids.size}首歌曲")
}.onFailure { exception ->
Log.e(TAG, "QQ音乐播放列表启动失败: ${exception.message}")
}
}
} else {
Log.e(TAG, "音乐列表中没有有效的mid,未启动播放服务")
}
} else {
Log.e(TAG, "音乐列表为空,未启动播放服务")
}
}
/**
* 处理导航
* 将ai返回的音乐连接 在后台启动播放

66
local_plugins/chat_api/android/src/main/kotlin/com/yunqiinnovation/chat_api/QQMusicSystemFunctionHandler.kt

@ -20,8 +20,8 @@ class QQMusicSystemFunctionHandler(private val context: Context? = null) {
try {
// Only register QQ Music search function
client.registerLocalFunction(
"qqmusic_search_songs",
"在QQ音乐中搜索歌曲,支持歌曲、专辑、歌手等搜索类型",
"qqmusic_searchandplay_songs",
"在QQ音乐中搜索并播放歌曲,支持歌曲、专辑、歌手等搜索类型",
mapOf(
"type" to "object",
"properties" to mapOf(
@ -41,38 +41,38 @@ class QQMusicSystemFunctionHandler(private val context: Context? = null) {
)
// QQ音乐播放歌曲
client.registerLocalFunction(
"qqmusic_play_songs",
"播放QQ音乐歌曲列表",
mapOf(
"type" to "object",
"properties" to mapOf(
"songMids" to mapOf(
"type" to "array",
"description" to "歌曲ID列表",
"items" to mapOf("type" to "string")
),
"index" to mapOf(
"type" to "integer",
"description" to "开始播放的歌曲索引,默认为0"
)
),
"required" to listOf("songMids")
),
QQMusicPlaySongsHandler(context)
)
// client.registerLocalFunction(
// "qqmusic_play_songs",
// "播放QQ音乐歌曲列表",
// mapOf(
// "type" to "object",
// "properties" to mapOf(
// "songMids" to mapOf(
// "type" to "array",
// "description" to "歌曲ID列表",
// "items" to mapOf("type" to "string")
// ),
// "index" to mapOf(
// "type" to "integer",
// "description" to "开始播放的歌曲索引,默认为0"
// )
// ),
// "required" to listOf("songMids")
// ),
// QQMusicPlaySongsHandler(context)
// )
// QQ音乐播放控制
client.registerLocalFunction(
"qqmusic_play",
"播放QQ音乐",
mapOf(
"type" to "object",
"properties" to emptyMap<String, Any>(),
"required" to emptyList<String>()
),
QQMusicPlayHandler(context)
)
// client.registerLocalFunction(
// "qqmusic_play",
// "播放QQ音乐",
// mapOf(
// "type" to "object",
// "properties" to emptyMap<String, Any>(),
// "required" to emptyList<String>()
// ),
// QQMusicPlayHandler(context)
// )
client.registerLocalFunction(
"qqmusic_pause",
@ -232,7 +232,7 @@ private class QQMusicSearchHandler(private val context: Context?) : FunctionHand
val duration = songMap["duration"] ?: 0
"{\"mid\": \"$mid\", \"name\": \"$name\", \"artist\": \"$artist\", \"album\": \"$album\", \"duration\":$duration,\"pic\": \"$pic\"}"
}
"{\"success\": true, \"message\": \"搜索成功\", \"data\": [$songsJson]}"
"{\"success\": true, \"message\": \"搜索成功,增在播放\", \"data\": [$songsJson]}"
} else {
val error = searchResult.exceptionOrNull()
"{\"success\": false, \"message\": \"搜索失败: ${error?.message}\"}"

1
local_plugins/qq_music/android/src/main/kotlin/com/yunqiinnovation/qq_music/QQMusicManager.kt

@ -62,6 +62,7 @@ class QQMusicManager(private val activity: Activity) {
}
init {
Log.d(TAG, "QQ音乐服务未连接,无法发送hi消息")
bindQQMusicApiService()
}

65
local_plugins/qq_music/android/src/main/kotlin/com/yunqiinnovation/qq_music/QqMusicPlugin.kt

@ -1,6 +1,7 @@
package com.yunqiinnovation.qq_music
import android.app.Activity
import android.util.Log
import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.embedding.engine.plugins.activity.ActivityAware
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding
@ -15,10 +16,51 @@ class QqMusicPlugin: FlutterPlugin, MethodCallHandler, ActivityAware {
private lateinit var channel: MethodChannel
private var activity: Activity? = null
private val qqMusicSingleton = QQMusicSingleton.getInstance()
private var isRegistered = false
override fun onAttachedToEngine(flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
if (isRegistered) {
Log.w("QqMusicPlugin", "Plugin already registered, skipping")
return
}
Log.d("QqMusicPlugin", "onAttachedToEngine called")
channel = MethodChannel(flutterPluginBinding.binaryMessenger, "com.yunqiinnovation.qq_music")
channel.setMethodCallHandler(this)
isRegistered = true
}
override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) {
Log.d("QqMusicPlugin", "onDetachedFromEngine called")
if (::channel.isInitialized) {
channel.setMethodCallHandler(null)
}
isRegistered = false
}
override fun onAttachedToActivity(binding: ActivityPluginBinding) {
Log.d("QqMusicPlugin", "onAttachedToActivity called")
activity = binding.activity
println("QQ音乐 onAttachedToActivity")
qqMusicSingleton.initialize(activity!!)
Log.d("QqMusicPlugin", "qqMusicSingleton.initialize completed")
}
override fun onReattachedToActivityForConfigChanges(binding: ActivityPluginBinding) {
Log.d("QqMusicPlugin", "onReattachedToActivityForConfigChanges called")
activity = binding.activity
// qqMusicSingleton.initialize(activity!!)
}
override fun onDetachedFromActivityForConfigChanges() {
Log.d("QqMusicPlugin", "onDetachedFromActivityForConfigChanges called")
activity = null
}
override fun onDetachedFromActivity() {
Log.d("QqMusicPlugin", "onDetachedFromActivity called")
activity = null
qqMusicSingleton.cleanup()
}
override fun onMethodCall(call: MethodCall, result: Result) {
@ -200,27 +242,4 @@ class QqMusicPlugin: FlutterPlugin, MethodCallHandler, ActivityAware {
}
}
}
override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) {
channel.setMethodCallHandler(null)
}
override fun onAttachedToActivity(binding: ActivityPluginBinding) {
activity = binding.activity
qqMusicSingleton.initialize(activity!!)
}
override fun onDetachedFromActivityForConfigChanges() {
activity = null
}
override fun onReattachedToActivityForConfigChanges(binding: ActivityPluginBinding) {
activity = binding.activity
qqMusicSingleton.initialize(activity!!)
}
override fun onDetachedFromActivity() {
activity = null
qqMusicSingleton.cleanup()
}
}

12
local_plugins/qq_music/lib/qq_music.dart

@ -180,6 +180,18 @@ class QqMusic {
throw Exception('同步播放信息失败: $e');
}
}
/// 获取平台版本
Future<String?> getPlatformVersion() async {
try {
final version = await _methodChannel.invokeMethod<String>(
'getPlatformVersion',
);
return version;
} on PlatformException catch (e) {
throw Exception('获取平台版本失败: ${e.message}');
}
}
}
/// 登录结果类

Loading…
Cancel
Save