Browse Source

Merge commit '23c3ad422245f76faef1a6975f3739f9bfa9b4f2' into new_dev

weicu
lxm 1 year ago
parent
commit
1ea23cf8a1
  1. 2
      ios/Runner.xcodeproj/project.pbxproj
  2. 2
      ios/Runner/Info.plist
  3. 8
      lib/data/services/novice_guide_service.dart
  4. 26
      lib/modules/permissions/models/permission_group.dart
  5. 43
      lib/modules/permissions/views/permissions_view.dart
  6. 12
      local_plugins/agent_service/android/src/main/kotlin/com/yunqiinnovation/agent_service/AgentService.kt
  7. 7
      local_plugins/ble_service/ios/ble_service/Package.swift
  8. 16
      local_plugins/chat_api/android/src/main/kotlin/com/yunqiinnovation/chat_api/ChatApiService.kt
  9. 136
      local_plugins/chat_api/android/src/main/kotlin/com/yunqiinnovation/chat_api/QQMusicSystemFunctionHandler.kt
  10. 2
      local_plugins/jl_opus/pubspec.yaml
  11. 37
      local_plugins/qq_music/android/src/main/kotlin/com/yunqiinnovation/qq_music/QQMusicManager.kt
  12. 17
      local_plugins/qq_music/android/src/main/kotlin/com/yunqiinnovation/qq_music/QQMusicSingleton.kt
  13. 9
      pubspec.yaml

2
ios/Runner.xcodeproj/project.pbxproj

@ -45,7 +45,6 @@
/* Begin PBXFileReference section */
0AD944112DD9DB5C00557D21 /* GoogleService-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = "<group>"; };
0AD944132DDA0C0D00557D21 /* AccessorySetupKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AccessorySetupKit.framework; path = System/Library/Frameworks/AccessorySetupKit.framework; sourceTree = SDKROOT; };
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
162D67C21ED243BA396CEF5C /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
@ -109,7 +108,6 @@
1E5DDD8701F6FB27AA502080 /* Frameworks */ = {
isa = PBXGroup;
children = (
0AD944132DDA0C0D00557D21 /* AccessorySetupKit.framework */,
EFDA2C0DD7A7D82CA03799B2 /* Pods_Runner.framework */,
162D67C21ED243BA396CEF5C /* Pods_RunnerTests.framework */,
);

2
ios/Runner/Info.plist

@ -106,6 +106,8 @@
<string>Bluetooth permission is required to connect and manage audio devices</string>
<key>NSCalendarsUsageDescription</key>
<string>Calendar permission is required to schedule and manage your audio meetings and recording tasks</string>
<key>NSCalendarsFullAccessUsageDescription</key>
<string>Calendar permission is required to schedule and manage your audio meetings and recording tasks</string>
<key>NSCameraUsageDescription</key>
<string>Camera permission is required for QR code scanning and video calling functions</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>

8
lib/data/services/novice_guide_service.dart

@ -68,11 +68,11 @@ class NoviceGuideService extends GetxService {
'method': () async {
//创建会议提醒需要日历权限
await PermissionUtil.instance.requestPermission(
permissionType: Permission.calendarWriteOnly,
permissionName: 'calendarWrite'.tr, // 日历写入
explanationText: 'calendarWritePermissionDesc'.tr, // 用于创建日历事件和提醒
permissionType: Permission.calendarFullAccess,
permissionName: 'calendarFullAccess'.tr, // 日历写入
explanationText: 'calendarFullAccessPermissionDesc'.tr, // 用于创建日历事件和提醒
permanentDenialText:
'calendarWritePermissionDetailDesc'.tr, // 创建日历事件需要日历写入权限
'calendarFullAccessPermissionDetailDesc'.tr, // 创建日历事件需要日历写入权限
);
},
},

26
lib/modules/permissions/models/permission_group.dart

@ -3,17 +3,19 @@ import 'package:flutter/material.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:device_info_plus/device_info_plus.dart';
class PermissionGroup {
class PermissionGroupModel {
final String titleKey;
final IconData icon;
final List<Permission> permissions;
const PermissionGroup({
const PermissionGroupModel({
required this.titleKey,
required this.icon,
required this.permissions,
});
}
class PermissionGroup {
/// 获取蓝牙权限列表(根据平台和Android版本)
static Future<List<Permission>> _getBluetoothPermissions() async {
if (Platform.isAndroid) {
@ -41,55 +43,55 @@ class PermissionGroup {
}
/// 获取平台特定的权限组列表(异步方法)
static Future<List<PermissionGroup>> getPlatformGroups() async {
static Future<List<PermissionGroupModel>> getPlatformGroups() async {
// 动态获取蓝牙权限列表
final bluetoothPermissions = await _getBluetoothPermissions();
return [
// 通讯权限组 - 仅Android(包含联系人权限)
const PermissionGroup(
const PermissionGroupModel(
titleKey: 'communicationPermissions',
icon: Icons.phone_android,
permissions: [Permission.phone, Permission.sms, Permission.contacts],
),
// 蓝牙权限组 - 根据平台动态获取权限
PermissionGroup(
PermissionGroupModel(
titleKey: 'bluetoothPermissions',
icon: Icons.bluetooth,
permissions: bluetoothPermissions,
),
// 通知权限组
const PermissionGroup(
const PermissionGroupModel(
titleKey: 'notificationPermissions',
icon: Icons.notifications,
permissions: [Permission.notification],
),
// 闹钟权限组 - 仅Android
const PermissionGroup(
const PermissionGroupModel(
titleKey: 'alarmPermissions',
icon: Icons.alarm,
permissions: [Permission.scheduleExactAlarm],
),
// 日历权限组
const PermissionGroup(
const PermissionGroupModel(
titleKey: 'calendarPermissions',
icon: Icons.calendar_today,
permissions: [Permission.calendarFullAccess],
),
// 位置权限组
const PermissionGroup(
const PermissionGroupModel(
titleKey: 'locationPermissions',
icon: Icons.location_on,
permissions: [Permission.location],
),
// 存储权限组
const PermissionGroup(
const PermissionGroupModel(
titleKey: 'storagePermissions',
icon: Icons.storage,
permissions: [Permission.storage],
),
// 麦克风权限组
const PermissionGroup(
const PermissionGroupModel(
titleKey: 'microphonePermissions',
icon: Icons.mic,
permissions: [Permission.microphone],

43
lib/modules/permissions/views/permissions_view.dart

@ -4,7 +4,6 @@ import 'package:permission_handler/permission_handler.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'dart:ui';
import 'dart:io' show Platform;
import 'package:device_info_plus/device_info_plus.dart';
import '../controllers/permissions_controller.dart';
import '../models/permission_group.dart';
@ -56,23 +55,23 @@ class PermissionsView extends GetView<PermissionsController> {
}
Widget _buildPermissionGroups(bool isDarkMode) {
return FutureBuilder<List<PermissionGroup>>(
return FutureBuilder<List<PermissionGroupModel>>(
future: PermissionGroup.getPlatformGroups(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(child: CircularProgressIndicator());
}
if (snapshot.hasError) {
return Center(child: Text('加载权限组失败: ${snapshot.error}'));
}
final groups = snapshot.data ?? [];
final List<Widget> widgets = [];
for (int i = 0; i < groups.length; i++) {
final group = groups[i];
// 过滤平台特定权限
if (_shouldShowGroup(group)) {
widgets.add(_buildPermissionSection(
@ -82,21 +81,21 @@ class PermissionsView extends GetView<PermissionsController> {
controller.permissionStatuses,
isDarkMode,
));
if (i < groups.length - 1) {
widgets.add(SizedBox(height: 20.h));
}
}
}
return Column(children: widgets);
},
);
},
);
}
bool _shouldShowGroup(PermissionGroup group) {
bool _shouldShowGroup(PermissionGroupModel group) {
// Android特定权限组
if (group.titleKey == 'communicationPermissions' ||
if (group.titleKey == 'communicationPermissions' ||
group.titleKey == 'alarmPermissions') {
return Platform.isAndroid;
}
@ -162,7 +161,8 @@ class PermissionsView extends GetView<PermissionsController> {
? ImageFilter.blur(sigmaX: 5, sigmaY: 5)
: ImageFilter.blur(sigmaX: 0, sigmaY: 0),
child: Column(
children: _buildPermissionItems(permissions, statuses, isDarkMode),
children:
_buildPermissionItems(permissions, statuses, isDarkMode),
),
),
),
@ -238,12 +238,13 @@ class PermissionsView extends GetView<PermissionsController> {
),
),
Obx(() => Switch(
value: status.isGranted,
onChanged: controller.isRequestingPermission.value
? null
: (value) => _handlePermissionToggle(permission, status, value),
activeColor: Colors.blue[600],
)),
value: status.isGranted,
onChanged: controller.isRequestingPermission.value
? null
: (value) =>
_handlePermissionToggle(permission, status, value),
activeColor: Colors.blue[600],
)),
],
),
);
@ -281,8 +282,8 @@ class PermissionsView extends GetView<PermissionsController> {
}
void _handlePermissionToggle(
Permission permission,
PermissionStatus status,
Permission permission,
PermissionStatus status,
bool value,
) {
if (value) {
@ -293,4 +294,4 @@ class PermissionsView extends GetView<PermissionsController> {
controller.openSettings();
}
}
}
}

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

@ -131,6 +131,9 @@ object AgentService : CoroutineScope {
// 语音识别模式
private var currentRecognitionMode = "normal" // 当前识别模式:normal, ble_wakeup, phone_call, push_to_talk
//是否播放音乐中
private var isplaymusic = false;
// 打断防抖相关
private var lastInterruptTime = 0L
private val INTERRUPT_DEBOUNCE_MS = 300L
@ -358,6 +361,11 @@ object AgentService : CoroutineScope {
setPackage(context.packageName)
}
context.sendBroadcast(intent)
QQMusicSingleton.getInstance().autopauseMusic { result ->
if (result.isSuccess) {
isplaymusic = true
}
}
}
TtsEventType.PLAYBACK_COMPLETED -> { //结束AI播报内容
@ -369,6 +377,10 @@ object AgentService : CoroutineScope {
setPackage(context.packageName)
}
context.sendBroadcast(intent)
if(isplaymusic){
isplaymusic = false
QQMusicSingleton.getInstance().resumeMusic { }
}
}
TtsEventType.ERROR -> {

7
local_plugins/ble_service/ios/ble_service/Package.swift

@ -21,10 +21,9 @@ let package = Package(
linkerSettings: [
.linkedFramework("AVFoundation"),
.linkedFramework("AudioToolbox"),
.linkedFramework("CoreBluetooth"),
.linkedFramework("AccessorySetupKit", .when(platforms: [.iOS], configuration: .release)),
.linkedFramework("AccessorySetupKit", .when(platforms: [.iOS], configuration: .debug))
.linkedFramework("CoreBluetooth")
// 移除 AccessorySetupKit 链接,因为它只在 iOS 18+ 可用
]
)
]
)
)

16
local_plugins/chat_api/android/src/main/kotlin/com/yunqiinnovation/chat_api/ChatApiService.kt

@ -404,12 +404,24 @@ class ChatApiService(private val context: android.content.Context? = null) : Cor
throw IllegalStateException("OpenAI客户端未初始化")
}
Log.e("ChatApiService", "liwei---------,发送AI请求 model:${currentModel} messages:${chatMessages}")
val flow = openAI!!.chatCompletions(chatCompletionRequest)
// 添加超时控制,10秒超时
val flow = withTimeout(10.seconds) {
openAI!!.chatCompletions(chatCompletionRequest)
}
Log.d(TAG, "liwei-------------------------开始AI 对话 6")
flow
} catch (e: Exception) {
Log.e("ChatApiService", "创建ChatCompletionRequest或调用chatCompletions失败: ${e.message}", e)
throw e
if (sessionid == currSessionId) {
try {
getSessionCallback(sessionid)?.onError(sessionid,ChatApiException("流式请求失败: ${e.message}"))
} catch (ex: Exception) {
Log.e(TAG, "onError回调异常: ${ex.message}", ex)
}
clearCurrentSession()
}
return@launch
// throw e
}
var replyContext = "";

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

@ -4,6 +4,8 @@ import android.content.Context
import android.util.Log
import kotlinx.coroutines.delay
import com.yunqiinnovation.qq_music.QQMusicSingleton
import kotlin.coroutines.suspendCoroutine
import kotlin.coroutines.resume
/**
* QQ音乐系统功能处理器
* 负责注册QQ音乐相关的MCP函数
@ -195,60 +197,110 @@ private class QQMusicLoginHandler(private val context: Context?) : FunctionHandl
}
}
}
private class QQMusicSearchHandler(private val context: Context?) : FunctionHandler {
override suspend fun handle(arguments: Map<String, Any>): String {
return try {
val keyword = arguments["keyword"] as? String ?: return "{\"success\": false, \"message\": \"缺少搜索关键词\"}"
val searchType = arguments["searchType"] as? Int ?: 0 // 默认搜索歌曲
val qqMusicSingleton = QQMusicSingleton.getInstance()
var result = ""
// 直接调用搜索,内部会自动处理登录检查
qqMusicSingleton.searchSongs(keyword) { searchResult ->
result = if (searchResult.isSuccess) {
val songs = searchResult.getOrNull() ?: emptyList()
// 根据搜索类型处理结果
val processedSongs = when (searchType) {
0 -> { // 歌曲搜索,只返回第一个结果
// if (songs.isNotEmpty()) listOf(songs.first()) else emptyList()
songs
}
else -> { // 专辑、歌手等其他类型,返回所有结果
songs
// 使用 suspendCoroutine 将回调转换为协程
suspendCoroutine { continuation ->
qqMusicSingleton.searchSongs(keyword) { searchResult ->
val result = if (searchResult.isSuccess) {
val songs = searchResult.getOrNull() ?: emptyList()
// 根据搜索类型处理结果
val processedSongs = when (searchType) {
0 -> { // 歌曲搜索,返回所有结果
songs
}
else -> { // 专辑、歌手等其他类型,返回所有结果
songs
}
}
}
val songsJson = processedSongs.joinToString(",") { song ->
val songMap = song as Map<String, Any?>
// 添加调试日志
Log.d("QQMusicSearchHandler", "原始数据: $songMap")
// 修正字段名映射
val mid = songMap["mid"] ?: "unknown"
val name = songMap["name"] ?: "unknown"
val artist = songMap["singer"] ?: "unknown"
val album = songMap["album"] ?: ""
val pic = songMap["pic"] ?: ""
val duration = songMap["duration"] ?: 0
"{\"mid\": \"$mid\", \"name\": \"$name\", \"artist\": \"$artist\", \"album\": \"$album\", \"duration\":$duration,\"pic\": \"$pic\"}"
val songsJson = processedSongs.joinToString(",") { song ->
val songMap = song as Map<String, Any?>
// 添加调试日志
Log.d("QQMusicSearchHandler", "原始数据: $songMap")
// 修正字段名映射
val mid = songMap["mid"] ?: "unknown"
val name = songMap["name"] ?: "unknown"
val artist = songMap["singer"] ?: "unknown"
val album = songMap["album"] ?: ""
val pic = songMap["pic"] ?: ""
val duration = songMap["duration"] ?: 0
"{\"mid\": \"$mid\", \"name\": \"$name\", \"artist\": \"$artist\", \"album\": \"$album\", \"duration\":$duration,\"pic\": \"$pic\"}"
}
"{\"success\": true, \"broadcast\": false, \"message\": \"搜索成功,正在播放\", \"data\": [$songsJson]}"
} else {
val error = searchResult.exceptionOrNull()
"{\"success\": false, \"message\": \"搜索失败: ${error?.message}\"}"
}
"{\"success\": true, \"broadcast\": false, \"message\": \"搜索成功,增在播放\", \"data\": [$songsJson]}"
} else {
val error = searchResult.exceptionOrNull()
"{\"success\": false, \"message\": \"搜索失败: ${error?.message}\"}"
// 恢复协程执行
continuation.resume(result)
}
}
// 等待回调完成
delay(5000)
result.ifEmpty { "{\"success\": false, \"message\": \"搜索超时\"}" }
} catch (e: Exception) {
Log.e("QQMusicSearchHandler", "QQ音乐搜索失败", e)
"{\"success\": false, \"message\": \"搜索异常: ${e.message}\"}"
}
}
}
//private class QQMusicSearchHandler(private val context: Context?) : FunctionHandler {
// override suspend fun handle(arguments: Map<String, Any>): String {
// return try {
// val keyword = arguments["keyword"] as? String ?: return "{\"success\": false, \"message\": \"缺少搜索关键词\"}"
// val searchType = arguments["searchType"] as? Int ?: 0 // 默认搜索歌曲
// val qqMusicSingleton = QQMusicSingleton.getInstance()
// var result = ""
//
// // 直接调用搜索,内部会自动处理登录检查
// qqMusicSingleton.searchSongs(keyword) { searchResult ->
// result = if (searchResult.isSuccess) {
// val songs = searchResult.getOrNull() ?: emptyList()
//
// // 根据搜索类型处理结果
// val processedSongs = when (searchType) {
// 0 -> { // 歌曲搜索,只返回第一个结果
//// if (songs.isNotEmpty()) listOf(songs.first()) else emptyList()
// songs
// }
// else -> { // 专辑、歌手等其他类型,返回所有结果
// songs
// }
// }
//
// val songsJson = processedSongs.joinToString(",") { song ->
// val songMap = song as Map<String, Any?>
// // 添加调试日志
// Log.d("QQMusicSearchHandler", "原始数据: $songMap")
// // 修正字段名映射
// val mid = songMap["mid"] ?: "unknown"
// val name = songMap["name"] ?: "unknown"
// val artist = songMap["singer"] ?: "unknown"
// val album = songMap["album"] ?: ""
// val pic = songMap["pic"] ?: ""
// val duration = songMap["duration"] ?: 0
// "{\"mid\": \"$mid\", \"name\": \"$name\", \"artist\": \"$artist\", \"album\": \"$album\", \"duration\":$duration,\"pic\": \"$pic\"}"
// }
// "{\"success\": true, \"broadcast\": false, \"message\": \"搜索成功,增在播放\", \"data\": [$songsJson]}"
// } else {
// val error = searchResult.exceptionOrNull()
// "{\"success\": false, \"message\": \"搜索失败: ${error?.message}\"}"
// }
// }
//
// // 等待回调完成
// delay(5000)
// result.ifEmpty { "{\"success\": false, \"message\": \"搜索超时\"}" }
// } catch (e: Exception) {
// Log.e("QQMusicSearchHandler", "QQ音乐搜索失败", e)
// "{\"success\": false, \"message\": \"搜索异常: ${e.message}\"}"
// }
// }
//}
private class QQMusicPlaySongsHandler(private val context: Context?) : FunctionHandler {
override suspend fun handle(arguments: Map<String, Any>): String {
@ -310,7 +362,7 @@ private class QQMusicPauseHandler(private val context: Context?) : FunctionHandl
qqMusicSingleton.pauseMusic { pauseResult ->
result = if (pauseResult.isSuccess) {
"{\"notreply\": true, \"success\": true, \"message\": \"暂停播放\"}"
"{\"broadcast\": false, \"success\": true, \"message\": \"暂停播放\"}"
} else {
val error = pauseResult.exceptionOrNull()
"{\"success\": false, \"message\": \"暂停失败: ${error?.message}\"}"
@ -334,7 +386,7 @@ private class QQMusicResumeHandler(private val context: Context?) : FunctionHand
qqMusicSingleton.resumeMusic { resumeResult ->
result = if (resumeResult.isSuccess) {
"{\"notreply\": true, \"success\": true, \"message\": \"恢复播放\"}"
"{\"broadcast\": false, \"success\": true, \"message\": \"恢复播放\"}"
} else {
val error = resumeResult.exceptionOrNull()
"{\"success\": false, \"message\": \"恢复播放失败: ${error?.message}\"}"
@ -358,7 +410,7 @@ private class QQMusicStopHandler(private val context: Context?) : FunctionHandle
qqMusicSingleton.stopMusic { stopResult ->
result = if (stopResult.isSuccess) {
"{\"notreply\": true, \"success\": true, \"message\": \"停止播放\"}"
"{\"broadcast\": false, \"success\": true, \"message\": \"停止播放\"}"
} else {
val error = stopResult.exceptionOrNull()
"{\"success\": false, \"message\": \"停止失败: ${error?.message}\"}"
@ -382,7 +434,7 @@ private class QQMusicNextHandler(private val context: Context?) : FunctionHandle
qqMusicSingleton.skipToNext { nextResult ->
result = if (nextResult.isSuccess) {
"{\"notreply\": true, \"success\": true, \"message\": \"切换到下一首\"}"
"{\"broadcast\": false, \"success\": true, \"message\": \"切换到下一首\"}"
} else {
val error = nextResult.exceptionOrNull()
"{\"success\": false, \"message\": \"切换失败: ${error?.message}\"}"
@ -406,7 +458,7 @@ private class QQMusicPreviousHandler(private val context: Context?) : FunctionHa
qqMusicSingleton.skipToPrevious { previousResult ->
result = if (previousResult.isSuccess) {
"{\"notreply\": true, \"success\": true, \"message\": \"切换到上一首\"}"
"{\"broadcast\": false, \"success\": true, \"message\": \"切换到上一首\"}"
} else {
val error = previousResult.exceptionOrNull()
"{\"success\": false, \"message\": \"切换失败: ${error?.message}\"}"
@ -434,7 +486,7 @@ private class QQMusicGetPlaybackStateHandler(private val context: Context?) : Fu
val stateJson = state.entries.joinToString(",") { (key, value) ->
"\"$key\": \"$value\""
}
"{\"notreply\": true, \"success\": true, \"message\": \"获取播放状态成功\", \"data\": {$stateJson}}"
"{\"broadcast\": false, \"success\": true, \"message\": \"获取播放状态成功\", \"data\": {$stateJson}}"
} else {
val error = stateResult.exceptionOrNull()
"{\"success\": false, \"message\": \"获取播放状态失败: ${error?.message}\"}"

2
local_plugins/jl_opus/pubspec.yaml

@ -11,7 +11,7 @@ dependencies:
flutter:
sdk: flutter
path_provider: ^2.0.0
permission_handler: ^11.4.0
permission_handler: ^12.0.1
dev_dependencies:
flutter_test:

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

@ -319,6 +319,43 @@ class QQMusicManager(private val activity: Activity) {
}
}
fun autopauseMusic(callback: PlayCallback){
if (!isBindQQMusicService || qqmusicApi == null) {
callback.onError(-1, "QQ音乐服务未连接")
return
}
// 获取播放状态
val stateResult = qqmusicApi?.execute("getPlaybackState", null)
val stateCode = stateResult?.getInt(Keys.API_RETURN_KEY_CODE) ?: -1
// 处理播放状态 - 使用正确的常量
if (stateCode == ErrorCodes.ERROR_OK) {
val playState = stateResult?.getInt(Keys.API_RETURN_KEY_DATA) ?: 0
val isPlaying = when (playState) {
PlayState.STARTED -> true
PlayState.PREPARED -> true
PlayState.BUFFERING -> true
PlayState.PAUSED -> false
PlayState.STOPPED -> false
PlayState.ERROR -> false
else -> false
}
if(isPlaying){
val result = qqmusicApi?.execute("pauseMusic", null)
val code = result?.getInt(Keys.API_RETURN_KEY_CODE) ?: -1
if (code == ErrorCodes.ERROR_OK) {
callback.onSuccess()
} else {
callback.onError(code, "暂停失败")
}
}else {
callback.onError(-1, "未播放")
}
} else {
callback.onError(-1, "未播放")
}
}
/**
* 暂停音乐
*/

17
local_plugins/qq_music/android/src/main/kotlin/com/yunqiinnovation/qq_music/QQMusicSingleton.kt

@ -25,8 +25,8 @@ class QQMusicSingleton private constructor() {
private const val KEY_EXPIRE_TIME = "expire_time"
private const val LOGIN_WAIT_DELAY_MS = 30000L
// 添加搜索重试相关常量
private const val SEARCH_TIMEOUT_MS = 50000L
private const val MAX_RETRY_COUNT = 3
private const val SEARCH_TIMEOUT_MS = 10000L
private const val MAX_RETRY_COUNT = 1
private const val RETRY_DELAY_MS = 1000L
@Volatile
@ -194,7 +194,7 @@ class QQMusicSingleton private constructor() {
callback(Result.failure(Exception("未安装QQ音乐软件,请先安装QQ音乐软件")))
return
}
searchWithRetry(keyword, searchType, 0, callback)
searchWithRetry(keyword, searchType, 1, callback)
}
/**
@ -413,7 +413,16 @@ class QQMusicSingleton private constructor() {
musicManager.pauseMusic(playCallback)
}(callback)
}
/**
* 暂停音乐
*/
fun autopauseMusic(callback: (Result<Unit>) -> Unit) {
executePlaybackAction("自动暂停") { musicManager, playCallback ->
musicManager.autopauseMusic(playCallback)
}(callback)
}
/**
* 恢复播放
*/

9
pubspec.yaml

@ -28,7 +28,7 @@ dependencies:
htmltopdfwidgets: ^1.1.0
wifi_iot: ^0.3.19+2
flutter_intro: ^3.4.0
permission_handler: ^10.4.5
permission_handler: ^12.0.1
web_socket_channel: ^2.4.0
flutter_dotenv: ^5.1.0
synchronized: ^3.1.0
@ -53,7 +53,7 @@ dependencies:
flutter_local_notifications: ^18.0.1
device_info_plus: ^11.5.0
uuid: ^4.3.3
record: ^5.2.1
record: ^6.0.0
share_plus: ^11.0.0
image_picker: ^1.1.2
audio_waveforms: ^1.3.0
@ -119,11 +119,6 @@ dev_dependencies:
build_runner: ^2.3.3 # 用于生成代码 flutter pub run build_runner build
json_serializable: ^6.6.0 # 用于自动生成代码
dependency_overrides:
permission_handler: ^12.0.0
permission_handler_android: ^13.0.0
permission_handler_apple: ^9.4.0
flutter:
uses-material-design: true
shaders:

Loading…
Cancel
Save