Browse Source

优化qq音乐服务代码,修复搜索不主动播放的问题

weicu
liwei1dao 1 year ago
parent
commit
de6c1dc2f4
  1. 116
      local_plugins/chat_api/android/src/main/kotlin/com/yunqiinnovation/chat_api/QQMusicSystemFunctionHandler.kt
  2. 33
      local_plugins/qq_music/android/src/main/kotlin/com/yunqiinnovation/qq_music/QQMusicLoginManager.kt
  3. 96
      local_plugins/qq_music/android/src/main/kotlin/com/yunqiinnovation/qq_music/QQMusicManager.kt
  4. 424
      local_plugins/qq_music/android/src/main/kotlin/com/yunqiinnovation/qq_music/QQMusicSingleton.kt
  5. 16
      local_plugins/qq_music/android/src/main/kotlin/com/yunqiinnovation/qq_music/QqMusicPlugin.kt

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

@ -49,40 +49,6 @@ class QQMusicSystemFunctionHandler(private val context: Context? = null) {
QQMusicSearchHandler(context)
)
// 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)
// )
//QQ音乐播放控制
// client.registerLocalFunction(
// "qqmusic_play",
// "播放QQ音乐",
// mapOf(
// "type" to "object",
// "properties" to emptyMap<String, Any>(),
// "required" to emptyList<String>()
// ),
// QQMusicPlayHandler(context)
// )
client.registerLocalFunction(
"qqmusic_pause",
"暂停QQ音乐",
@ -138,39 +104,6 @@ class QQMusicSystemFunctionHandler(private val context: Context? = null) {
QQMusicPreviousHandler(context)
)
// QQ音乐状态查询
client.registerLocalFunction(
"qqmusic_get_playback_state",
"获取QQ音乐播放状态",
mapOf(
"type" to "object",
"properties" to emptyMap<String, Any>(),
"required" to emptyList<String>()
),
QQMusicGetPlaybackStateHandler(context)
)
client.registerLocalFunction(
"qqmusic_get_current_song",
"获取QQ音乐当前播放歌曲信息",
mapOf(
"type" to "object",
"properties" to emptyMap<String, Any>(),
"required" to emptyList<String>()
),
QQMusicGetCurrentSongHandler(context)
)
client.registerLocalFunction(
"qqmusic_get_play_time",
"获取QQ音乐播放时间信息",
mapOf(
"type" to "object",
"properties" to emptyMap<String, Any>(),
"required" to emptyList<String>()
),
QQMusicGetPlayTimeHandler(context)
)
Log.d(TAG, "QQ音乐所有功能注册完成")
} catch (e: Exception) {
Log.e(TAG, "注册QQ音乐功能失败: ${e.message}", e)
@ -179,31 +112,6 @@ class QQMusicSystemFunctionHandler(private val context: Context? = null) {
}
private class QQMusicLoginHandler(private val context: Context?) : FunctionHandler {
override suspend fun handle(arguments: Map<String, Any>): String {
return try {
val qqMusicSingleton = QQMusicSingleton.getInstance()
var result = ""
qqMusicSingleton.login { loginResult ->
result = if (loginResult.isSuccess) {
val loginData = loginResult.getOrNull()
"{\"success\": true, \"message\": \"登录成功\", \"data\": {\"openId\": \"${loginData?.openId}\", \"openToken\": \"${loginData?.openToken}\", \"expireTime\": \"${loginData?.expireTime}\"}}"
} else {
val error = loginResult.exceptionOrNull()
"{\"success\": false, \"message\": \"登录失败: ${error?.message}\"}"
}
}
// 等待回调完成
delay(3000)
result.ifEmpty { "{\"success\": false, \"message\": \"登录超时\"}" }
} catch (e: Exception) {
Log.e("QQMusicLoginHandler", "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 {
@ -537,27 +445,3 @@ private class QQMusicGetCurrentSongHandler(private val context: Context?) : Func
}
}
private class QQMusicGetPlayTimeHandler(private val context: Context?) : FunctionHandler {
override suspend fun handle(arguments: Map<String, Any>): String {
return try {
val qqMusicSingleton = QQMusicSingleton.getInstance()
var result = ""
qqMusicSingleton.getPlayTime { timeResult ->
result = if (timeResult.isSuccess) {
val timeInfo = timeResult.getOrNull()
"{\"success\": true, \"message\": \"获取播放时间成功\", \"data\": {\"totalTime\": ${timeInfo?.totalTime}, \"currentTime\": ${timeInfo?.currentTime}}}"
} else {
val error = timeResult.exceptionOrNull()
"{\"success\": false, \"message\": \"获取播放时间失败: ${error?.message}\"}"
}
}
delay(2000)
result.ifEmpty { "{\"success\": false, \"message\": \"获取播放时间超时\"}" }
} catch (e: Exception) {
Log.e("QQMusicLoginHandler", "获取QQ音乐播放时间失败", e)
"{\"success\": false, \"message\": \"获取播放时间异常: ${e.message}\"}"
}
}
}

33
local_plugins/qq_music/android/src/main/kotlin/com/yunqiinnovation/qq_music/QQMusicLoginManager.kt

@ -27,7 +27,7 @@ class QQMusicLoginManager(private val context: Context) {
// 定义错误码常量,替代 LoginExampleActivity 中的常量
const val LOGIN_FAILED = 1
}
private var isBindQQMusicService = false
private lateinit var qPlayBindHelper: QPlayBindHelper
private var qqMusicApi: IQQMusicApi? = null
private lateinit var qqMusicApiWrapper: QQMusicApiWrapper
@ -37,10 +37,15 @@ class QQMusicLoginManager(private val context: Context) {
* 登录结果回调接口
*/
interface LoginCallback {
fun onSuccess(openId: String, openToken: String, expireTime: String)
fun onSuccess()
fun onError(errorCode: String, errorMessage: String)
}
//是否连接
public val isLogined: Boolean
get() = isBindQQMusicService && qPlayBindHelper != null
/**
* 开始登录流程
*/
@ -101,8 +106,8 @@ class QQMusicLoginManager(private val context: Context) {
ErrorCodes.ERROR_OK -> {
// 已授权,直接请求登录信息
Log.d(TAG, "已授权,直接获取登录信息")
callback.onSuccess("","","")
// requestAuth(callback)
isBindQQMusicService = true
callback.onSuccess()
}
ErrorCodes.ERROR_API_NO_PERMISSION -> {
// 需要授权
@ -110,12 +115,14 @@ class QQMusicLoginManager(private val context: Context) {
startAuthProcess(callback)
}
else -> {
isBindQQMusicService = false
Log.e(TAG, "检查授权状态失败: $code")
callback.onError("AUTH_CHECK_FAILED", "检查授权状态失败")
}
}
} catch (e: Exception) {
Log.e(TAG, "检查授权状态异常", e)
isBindQQMusicService = false
callback.onError("AUTH_CHECK_ERROR", "检查授权状态异常: ${e.message}")
}
}
@ -172,7 +179,7 @@ class QQMusicLoginManager(private val context: Context) {
},
failed = { errorCode, errorMsg ->
Log.e(TAG, "授权失败: code=$errorCode, msg=$errorMsg")
isBindQQMusicService = false
val errorMessage = when (errorCode) {
LOGIN_FAILED -> "登录失败: $errorMsg"
else -> "授权失败: $errorMsg"
@ -197,22 +204,23 @@ class QQMusicLoginManager(private val context: Context) {
// 检查签名
if (OpenIDHelper.checkQMSign(sign, returnNonce)) {
val openId = appDecryptJson.getString(Keys.API_RETURN_KEY_OPEN_ID)
val openToken = appDecryptJson.getString(Keys.API_RETURN_KEY_OPEN_TOKEN)
val expireTime = appDecryptJson.getString(Keys.API_PARAM_KEY_SDK_EXPIRETIME)
Log.d(TAG, "登录成功: openId=$openId")
// val openId = appDecryptJson.getString(Keys.API_RETURN_KEY_OPEN_ID)
// val openToken = appDecryptJson.getString(Keys.API_RETURN_KEY_OPEN_TOKEN)
// val expireTime = appDecryptJson.getString(Keys.API_PARAM_KEY_SDK_EXPIRETIME)
// Log.d(TAG, "登录成功: openId=$openId")
isBindQQMusicService = true
handler.post {
callback.onSuccess(openId, openToken, expireTime)
callback.onSuccess()
}
} else {
isBindQQMusicService = false
Log.e(TAG, "签名验证失败")
handler.post {
callback.onError("SIGN_ERROR", "签名验证失败")
}
}
} else {
isBindQQMusicService = false
Log.e(TAG, "解密失败")
handler.post {
callback.onError("DECRYPT_ERROR", "解密失败")
@ -220,6 +228,7 @@ class QQMusicLoginManager(private val context: Context) {
}
} catch (e: Exception) {
Log.e(TAG, "解析登录结果失败", e)
isBindQQMusicService = false
handler.post {
callback.onError("PARSE_ERROR", "解析登录结果失败: ${e.message}")
}

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

@ -40,37 +40,26 @@ class QQMusicManager(private val context: Context) {
fun onError(errorCode: Int, errorMessage: String)
}
private val serviceConnection = object : ServiceConnection {
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
Log.d(TAG, "QQ音乐服务连接成功")
qqmusicApi = IQQMusicApi.Stub.asInterface(service)
isBindQQMusicService = true
// 初始化SDK
CommonCmd.init(Config.BIND_PLATFORM)
// 延迟发送hi消息,确保Binder连接稳定
Handler(Looper.getMainLooper()).postDelayed({
sayHi()
}, 500) // 延迟500ms
}
override fun onServiceDisconnected(name: ComponentName?) {
Log.d(TAG, "QQ音乐服务连接断开")
qqmusicApi = null
isBindQQMusicService = false
//重连绑定
bindQQMusicApiService();
}
// 新增:绑定服务的回调接口
interface BindCallback {
fun onSuccess()
fun onError(errorCode: Int, errorMessage: String)
}
init {
bindQQMusicApiService()
// bindQQMusicApiService()
}
//是否连接
public val isConnected: Boolean
get() = isBindQQMusicService && qqmusicApi != null
private fun sayHi() {
if (!isBindQQMusicService || qqmusicApi == null) {
Log.w(TAG, "QQ音乐服务未连接,无法发送hi消息")
Log.w(TAG, "连接QQ音乐失败,可能是QQ音乐帐号状态异常,请打开QQ音乐检查帐号状态是否异常?")
return
}
@ -97,7 +86,7 @@ class QQMusicManager(private val context: Context) {
}
}
fun bindQQMusicApiService() {
fun bindQQMusicApiService(callback: BindCallback? = null) {
Log.d(TAG, "开始绑定QQ音乐服务,平台类型: ${Config.BIND_PLATFORM}")
val intent = when (Config.BIND_PLATFORM) {
@ -118,6 +107,7 @@ class QQMusicManager(private val context: Context) {
}
else -> {
Log.e(TAG, "不支持的平台类型: ${Config.BIND_PLATFORM}")
callback?.onError(-1, "不支持的平台类型: ${Config.BIND_PLATFORM}")
return
}
}
@ -125,7 +115,34 @@ class QQMusicManager(private val context: Context) {
Log.d(TAG, "绑定Intent: action=${intent.action}, package=${intent.`package`}")
try {
val bindResult = context.bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE)
val bindResult = context.bindService(intent, object : ServiceConnection {
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
Log.d(TAG, "QQ音乐服务连接成功")
qqmusicApi = IQQMusicApi.Stub.asInterface(service)
isBindQQMusicService = true
// 初始化SDK
CommonCmd.init(Config.BIND_PLATFORM)
// 延迟发送hi消息,确保Binder连接稳定
Handler(Looper.getMainLooper()).postDelayed({
sayHi()
// 绑定成功后调用回调
callback?.onSuccess()
}, 500) // 延迟500ms
}
override fun onServiceDisconnected(name: ComponentName?) {
Log.d(TAG, "QQ音乐服务连接断开")
qqmusicApi = null
isBindQQMusicService = false
// 服务断开时通知错误
callback?.onError(-2, "QQ音乐服务连接断开")
//重连绑定
bindQQMusicApiService(callback)
}
}, Context.BIND_AUTO_CREATE)
Log.d(TAG, "bindService结果: $bindResult")
if (!bindResult) {
@ -135,12 +152,34 @@ class QQMusicManager(private val context: Context) {
// 延迟重试绑定
Handler(Looper.getMainLooper()).postDelayed({
Log.d(TAG, "重试绑定QQ音乐服务")
context.bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE)
val retryResult = context.bindService(intent, object : ServiceConnection {
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
Log.d(TAG, "QQ音乐服务连接成功")
qqmusicApi = IQQMusicApi.Stub.asInterface(service)
isBindQQMusicService = true
// 初始化SDK
CommonCmd.init(Config.BIND_PLATFORM)
// 延迟发送hi消息,确保Binder连接稳定
Handler(Looper.getMainLooper()).postDelayed({
sayHi()
callback?.onSuccess()
}, 500) // 延迟500ms
}
override fun onServiceDisconnected(name: ComponentName?) {
Log.d(TAG, "QQ音乐服务连接断开")
qqmusicApi = null
isBindQQMusicService = false
}
}, Context.BIND_AUTO_CREATE)
Log.d(TAG, "重试绑定QQ音乐服务 $retryResult")
if (!retryResult) {
callback?.onError(-3, "重试绑定QQ音乐服务失败")
}
}, 2000)
}
} catch (e: Exception) {
Log.e(TAG, "绑定QQ音乐服务异常", e)
callback?.onError(-4, "绑定QQ音乐服务异常: ${e.message}")
}
}
@ -659,7 +698,6 @@ class QQMusicManager(private val context: Context) {
fun cleanup() {
try {
if (isBindQQMusicService) {
context.unbindService(serviceConnection)
isBindQQMusicService = false
Log.d(TAG, "QQ音乐服务已解绑")
}

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

@ -8,8 +8,6 @@ import android.os.Handler
import android.os.Looper
import android.util.Log
import com.tencent.qqmusic.third.api.contract.*
import java.text.SimpleDateFormat
import java.util.*
/**
* QQ音乐单例管理器
@ -23,11 +21,6 @@ class QQMusicSingleton private constructor() {
private const val KEY_OPEN_ID = "open_id"
private const val KEY_OPEN_TOKEN = "open_token"
private const val KEY_EXPIRE_TIME = "expire_time"
private const val LOGIN_WAIT_DELAY_MS = 30000L
// 添加搜索重试相关常量
private const val SEARCH_TIMEOUT_MS = 10000L
private const val MAX_RETRY_COUNT = 1
private const val RETRY_DELAY_MS = 1000L
@Volatile
private var INSTANCE: QQMusicSingleton? = null
@ -53,9 +46,9 @@ class QQMusicSingleton private constructor() {
*/
fun initialize(context: Context) {
this.context = context
this.sharedPreferences = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE)
loadSavedLoginInfo()
Log.d(TAG, "QQ音乐单例初始化完成")
// this.sharedPreferences = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE)
// loadSavedLoginInfo()
// Log.d(TAG, "QQ音乐单例初始化完成")
}
/**
* 检查QQ音乐App是否已安装
@ -87,58 +80,54 @@ class QQMusicSingleton private constructor() {
* 检查是否已登录且未过期
*/
fun isLoggedIn(): Boolean {
if (currentLoginResult == null){
loadSavedLoginInfo()
if (currentLoginResult == null){
return false
}
return true
}else{
return true
}
}
/**
* 获取当前登录信息
*/
fun getCurrentLoginInfo(): LoginResult? {
return if (isLoggedIn()) currentLoginResult else null
return loginManager != null && loginManager!!.isLogined
}
/**
* 登录接口
*/
fun login(callback: (Result<LoginResult>) -> Unit) {
fun login(callback: (Result<Unit>) -> Unit) {
if (!isQQMusicInstalled()){
callback(Result.failure(Exception("未安装QQ音乐软件,请先安装QQ音乐软件")))
return
}
val currentActivity = context
val currentContext = context
// 先检查是否已经登录且未过期
if (isLoggedIn()) {
Log.d(TAG, "用户已登录且未过期,直接返回登录信息")
ensureMusicManager(currentActivity!!)
callback(Result.success(currentLoginResult!!))
ensureMusicManager(currentContext!!,object: QQMusicManager. BindCallback{
override fun onSuccess() {
callback(Result.success(Unit))
}
override fun onError(errorCode: Int, errorMessage: String) {
callback(Result.failure(Exception("no logined $errorMessage")))
}
})
return
}
if (currentActivity == null) {
if (currentContext == null) {
callback(Result.failure(Exception("Activity not available")))
return
}
Log.d(TAG, "开始新的登录流程")
loginManager = QQMusicLoginManager(currentActivity)
loginManager = QQMusicLoginManager(currentContext)
loginManager?.startLogin(object : QQMusicLoginManager.LoginCallback {
override fun onSuccess(openId: String, openToken: String, expireTime: String) {
override fun onSuccess() {
handler.post {
ensureMusicManager(currentActivity!!)
val result = LoginResult(openId, openToken, expireTime)
currentLoginResult = result
saveLoginInfo(result)
Log.d(TAG, "登录成功并已保存: $result")
callback(Result.success(result))
ensureMusicManager(currentContext,object: QQMusicManager. BindCallback{
override fun onSuccess() {
callback(Result.success(Unit))
}
override fun onError(errorCode: Int, errorMessage: String) {
callback(Result.failure(Exception("no logined $errorMessage")))
}
})
}
}
@ -164,8 +153,16 @@ class QQMusicSingleton private constructor() {
// 先检查是否已经登录且未过期
if (isLoggedIn()) {
Log.d(TAG, "用户已登录且未过期,直接返回登录信息")
ensureMusicManager(currentActivity!!)
callback(Result.success(currentLoginResult!!))
ensureMusicManager(currentActivity!!,object: QQMusicManager. BindCallback{
override fun onSuccess() {
callback(Result.success(currentLoginResult!!))
}
override fun onError(errorCode: Int, errorMessage: String) {
callback(Result.failure(Exception("no logined $errorMessage")))
}
})
return
}else{
callback(Result.failure(Exception("no logined")))
@ -190,128 +187,11 @@ class QQMusicSingleton private constructor() {
searchType: Int = Data.SearchType.SEARCH_TYPE_SONG,
callback: (Result<List<Map<String, Any?>>>) -> Unit
) {
if (!isQQMusicInstalled()){
callback(Result.failure(Exception("未安装QQ音乐软件,请先安装QQ音乐软件")))
return
}
searchWithRetry(keyword, searchType, 1, callback)
}
/**
* 带重试的搜索实现
*/
private fun searchWithRetry(
keyword: String,
searchType: Int,
retryCount: Int,
callback: (Result<List<Map<String, Any?>>>) -> Unit
) {
val currentActivity = context
if (currentActivity == null) {
callback(Result.failure(Exception("Activity not available")))
return
}
// 检查登录状态
if (!isLoggedIn()) {
Log.d(TAG, "搜索前检测到未登录,开始自动登录")
login { loginResult ->
if (loginResult.isSuccess) {
Log.d(TAG, "自动登录成功,等待QQ音乐服务连接...")
handler.postDelayed({
Log.d(TAG, "等待完成,开始搜索")
performSearchWithTimeout(keyword, searchType, retryCount, callback)
}, LOGIN_WAIT_DELAY_MS)
} else {
callback(Result.failure(Exception("自动登录失败: ${loginResult.exceptionOrNull()?.message}")))
}
}
} else {
performSearchWithTimeout(keyword, searchType, retryCount, callback)
}
executeSearchbackAction("搜索歌曲",0,2) { musicManager, searchCallback ->
musicManager.searchSongs(keyword,searchType,searchCallback)
}(callback)
}
/**
* 执行带超时的搜索操作
*/
private fun performSearchWithTimeout(
keyword: String,
searchType: Int,
retryCount: Int,
callback: (Result<List<Map<String, Any?>>>) -> Unit
) {
val currentActivity = context ?: return
val searchKey = "${keyword}_${System.currentTimeMillis()}"
var completed = false
Log.d(TAG, "开始搜索: $keyword (第${retryCount + 1}次)")
// 设置超时
val timeoutRunnable = Runnable {
if (!completed) {
completed = true
searchTimeouts.remove(searchKey)
Log.w(TAG, "搜索超时: $keyword")
if (retryCount < MAX_RETRY_COUNT) {
Log.d(TAG, "准备重试: ${retryCount + 1}/$MAX_RETRY_COUNT")
handler.postDelayed({
searchWithRetry(keyword, searchType, retryCount + 1, callback)
}, RETRY_DELAY_MS)
} else {
callback(Result.failure(Exception("搜索超时,已重试${MAX_RETRY_COUNT}次")))
}
}
}
searchTimeouts[searchKey] = timeoutRunnable
handler.postDelayed(timeoutRunnable, SEARCH_TIMEOUT_MS)
ensureMusicManager(currentActivity)
musicManager?.searchSongs(keyword, searchType, object : QQMusicManager.SearchCallback {
override fun onSuccess(songs: List<Map<String, Any?>>) {
handler.post {
if (!completed) {
completed = true
searchTimeouts.remove(searchKey)?.let { handler.removeCallbacks(it) }
Log.d(TAG, "搜索成功: 找到 ${songs.size} 首歌曲")
callback(Result.success(songs))
}
}
}
override fun onError(errorCode: Int, errorMessage: String) {
handler.post {
if (!completed) {
completed = true
searchTimeouts.remove(searchKey)?.let { handler.removeCallbacks(it) }
Log.e(TAG, "搜索失败: code=$errorCode, message=$errorMessage")
// 如果是登录相关错误,清除本地登录信息
if (errorMessage.contains("登录") || errorMessage.contains("授权")) {
Log.d(TAG, "检测到登录相关错误,清除本地登录信息")
logout()
}
// 网络相关错误才重试
if (retryCount < MAX_RETRY_COUNT &&
(errorMessage.contains("网络") || errorMessage.contains("超时") ||
errorMessage.contains("连接") || errorCode == -1)) {
Log.d(TAG, "网络错误,准备重试: ${retryCount + 1}/$MAX_RETRY_COUNT")
if (errorCode == -1){
musicManager?.bindQQMusicApiService()
}
handler.postDelayed({
searchWithRetry(keyword, searchType, retryCount + 1, callback)
}, RETRY_DELAY_MS)
} else {
callback(Result.failure(Exception("搜索失败: $errorMessage")))
}
}
}
}
})
}
/**
* 播放歌曲列表(带自动登录检查)
@ -321,8 +201,8 @@ class QQMusicSingleton private constructor() {
index: Int = 0,
callback: (Result<Unit>) -> Unit
) {
Log.e(TAG, "播放音乐列表: $songMids")
executePlaybackAction("播放列表") { musicManager, playCallback ->
executePlaybackAction("播放列表",0,2) { musicManager, playCallback ->
Log.d(TAG, "播放歌曲:${songMids[index]}")
musicManager.playSongs(songMids, index,playCallback)
}(callback)
}
@ -331,7 +211,7 @@ class QQMusicSingleton private constructor() {
* 播放音乐
*/
fun playMusic(callback: (Result<Unit>) -> Unit) {
executePlaybackAction("播放") { musicManager, playCallback ->
executePlaybackAction("播放",0,2) { musicManager, playCallback ->
musicManager.playMusic(playCallback)
}(callback)
}
@ -386,11 +266,12 @@ class QQMusicSingleton private constructor() {
}
})
}
/**
* 恢复播放
*/
fun resumeMusic(callback: (Result<Unit>) -> Unit) {
executePlaybackAction("恢复播放") { musicManager, playCallback ->
executePlaybackAction("恢复播放",0,0) { musicManager, playCallback ->
musicManager.resumeMusic(playCallback)
}(callback)
}
@ -399,7 +280,7 @@ class QQMusicSingleton private constructor() {
* 停止音乐
*/
fun stopMusic(callback: (Result<Unit>) -> Unit) {
executePlaybackAction("停止") { musicManager, playCallback ->
executePlaybackAction("停止",0,0) { musicManager, playCallback ->
musicManager.stopMusic(playCallback)
}(callback)
}
@ -408,7 +289,7 @@ class QQMusicSingleton private constructor() {
* 下一首
*/
fun skipToNext(callback: (Result<Unit>) -> Unit) {
executePlaybackAction("下一首") { musicManager, playCallback ->
executePlaybackAction("下一首",0,0) { musicManager, playCallback ->
musicManager.skipToNext(playCallback)
}(callback)
}
@ -417,7 +298,7 @@ class QQMusicSingleton private constructor() {
* 上一首
*/
fun skipToPrevious(callback: (Result<Unit>) -> Unit) {
executePlaybackAction("上一首") { musicManager, playCallback ->
executePlaybackAction("上一首",0,0) { musicManager, playCallback ->
musicManager.skipToPrevious(playCallback)
}(callback)
}
@ -443,60 +324,20 @@ class QQMusicSingleton private constructor() {
/**
* 获取播放时间
*/
fun getPlayTime(callback: (Result<PlayTimeInfo>) -> Unit) {
val currentActivity = context
if (currentActivity == null) {
callback(Result.failure(Exception("Activity not available")))
return
}
ensureMusicManager(currentActivity)
musicManager?.getPlayTime(object : QQMusicManager.InfoCallback {
override fun onSuccess(data: Map<String, Any?>) {
handler.post {
val totalTime = data["totalTime"] as? Long ?: 0L
val currentTime = data["currentTime"] as? Long ?: 0L
val playTimeInfo = PlayTimeInfo(totalTime, currentTime)
Log.d(TAG, "获取播放时间成功: $playTimeInfo")
callback(Result.success(playTimeInfo))
}
}
fun getPlayTime(callback: (Result<Map<String, Any?>>) -> Unit) {
executeInfoAction("获取播放时间") { musicManager, infoCallback ->
musicManager.getPlayTime(infoCallback)
}(callback)
override fun onError(errorCode: Int, errorMessage: String) {
handler.post {
Log.e(TAG, "获取播放时间失败: $errorMessage")
callback(Result.failure(Exception("获取播放时间失败: $errorMessage")))
}
}
})
}
/**
* 同步当前播放信息 - 统一接口
*/
fun syncCurrentPlayInfo(callback: (Result<Map<String, Any?>>) -> Unit) {
val currentcontext = context
if (currentcontext == null) {
callback(Result.failure(Exception("Activity not available")))
return
}
ensureMusicManager(currentcontext)
musicManager?.syncCurrentPlayInfo(object : QQMusicManager.InfoCallback {
override fun onSuccess(data: Map<String, Any?>) {
handler.post {
Log.d(TAG, "同步播放信息成功")
callback(Result.success(data))
}
}
override fun onError(errorCode: Int, errorMessage: String) {
handler.post {
Log.e(TAG, "同步播放信息失败: $errorMessage")
callback(Result.failure(Exception("同步播放信息失败: $errorMessage")))
}
}
})
executeInfoAction("同步当前播放信息") { musicManager, infoCallback ->
musicManager.syncCurrentPlayInfo(infoCallback)
}(callback)
}
/**
@ -561,14 +402,81 @@ class QQMusicSingleton private constructor() {
}
// 私有辅助方法
private fun ensureMusicManager(context: Context) {
private fun ensureMusicManager(context: Context,callback: QQMusicManager. BindCallback) {
if (musicManager == null) {
musicManager = QQMusicManager(context)
musicManager!!.bindQQMusicApiService(callback)
}else{
if(!musicManager!!.isConnected) { //未连接
musicManager?.bindQQMusicApiService(callback)
}else{
callback.onSuccess()
}
}
}
private fun executeSearchbackAction(
actionName: String,
curragain:Int,
allagain:Int,
action: (QQMusicManager, QQMusicManager.SearchCallback) -> Unit
): (callback: (Result<List<Map<String, Any?>>>) -> Unit) -> Unit {
return lambda@{ callback ->
if (!isQQMusicInstalled()){
callback(Result.failure(Exception("未安装QQ音乐软件,请先安装QQ音乐软件")))
return@lambda
}
val currentActivity = context
if (currentActivity == null) {
callback(Result.failure(Exception("Activity not available")))
return@lambda
}
Log.d(TAG, "开始 ${actionName}")
ensureMusicManager(currentActivity,object: QQMusicManager. BindCallback{
override fun onSuccess(){
action(musicManager!!, object : QQMusicManager.SearchCallback {
override fun onSuccess(songs: List<Map<String, Any?>>) {
Log.d(TAG, "${actionName} 成功")
handler.post {
callback(Result.success(songs))
}
}
override fun onError(errorCode: Int, errorMessage: String) {
Log.d(TAG, "失败 ${actionName} 成功")
if (allagain > 0 && curragain < allagain){ //重试机制
executeSearchbackAction(actionName,curragain+1,allagain,action)
}else{
handler.post {
callback(Result.failure(Exception("$actionName 失败: $errorMessage")))
}
}
}
})
}
override fun onError(errorCode: Int, errorMessage: String) {
if (allagain > 0 && curragain < allagain){ //重试机制
executeSearchbackAction(actionName,curragain+1,allagain,action)
}else{
handler.post {
callback(Result.failure(Exception("$actionName 失败: $errorMessage")))
}
}
}
})
}
}
private fun executePlaybackAction(
actionName: String,
curragain:Int,
allagain:Int,
action: (QQMusicManager, QQMusicManager.PlayCallback) -> Unit
): (callback: (Result<Unit>) -> Unit) -> Unit {
return lambda@{ callback ->
@ -583,30 +491,42 @@ class QQMusicSingleton private constructor() {
callback(Result.failure(Exception("Activity not available")))
return@lambda
}
Log.d(TAG, "开始 ${actionName}")
ensureMusicManager(currentActivity,object: QQMusicManager. BindCallback{
override fun onSuccess(){
action(musicManager!!, object : QQMusicManager.PlayCallback {
override fun onSuccess() {
Log.d(TAG, "${actionName}成功")
handler.post {
callback(Result.success(Unit))
}
}
ensureMusicManager(currentActivity)
action(musicManager!!, object : QQMusicManager.PlayCallback {
override fun onSuccess() {
handler.post {
Log.d(TAG, "${actionName}成功")
callback(Result.success(Unit))
}
}
override fun onError(errorCode: Int, errorMessage: String) {
if (allagain > 0 && curragain < allagain){ //重试机制
executePlaybackAction(actionName,curragain+1,allagain,action)
}else{
handler.post {
Log.e(TAG, "${actionName}失败: $errorCode $errorMessage")
if (errorCode == -1){
musicManager?.bindQQMusicApiService()
callback(Result.failure(Exception("播放失败: $errorMessage")))
} else if (errorCode == 1030) {
callback(Result.success(Unit))
}else{
callback(Result.failure(Exception("播放失败: $errorMessage")))
}
}
}
override fun onError(errorCode: Int, errorMessage: String) {
handler.post {
Log.e(TAG, "播放失败: $errorCode $errorMessage")
if (errorCode == -1){
musicManager?.bindQQMusicApiService()
callback(Result.failure(Exception("播放失败: $errorMessage")))
} else if (errorCode == 1030) {
callback(Result.success(Unit))
}else{
callback(Result.failure(Exception("播放失败: $errorMessage")))
}
}
})
}
override fun onError(errorCode: Int, errorMessage: String) {
callback(Result.failure(Exception("$actionName 失败: $errorMessage")))
}
})
}
}
@ -615,26 +535,36 @@ class QQMusicSingleton private constructor() {
action: (QQMusicManager, QQMusicManager.InfoCallback) -> Unit
): (callback: (Result<Map<String, Any?>>) -> Unit) -> Unit {
return lambda@{ callback ->
if (!isQQMusicInstalled()){
callback(Result.failure(Exception("未安装QQ音乐软件,请先安装QQ音乐软件")))
return@lambda
}
val currentcontext = context
if (currentcontext == null) {
callback(Result.failure(Exception("Activity not available")))
return@lambda
}
ensureMusicManager(currentcontext)
action(musicManager!!, object : QQMusicManager.InfoCallback {
override fun onSuccess(data: Map<String, Any?>) {
handler.post {
Log.d(TAG, "${actionName}成功")
callback(Result.success(data))
}
}
ensureMusicManager(currentcontext,object: QQMusicManager. BindCallback{
override fun onSuccess(){
action(musicManager!!, object : QQMusicManager.InfoCallback {
override fun onSuccess(data: Map<String, Any?>) {
handler.post {
Log.d(TAG, "${actionName}成功")
callback(Result.success(data))
}
}
override fun onError(errorCode: Int, errorMessage: String) {
handler.post {
Log.e(TAG, "${actionName}失败: $errorMessage")
callback(Result.failure(Exception("${actionName}失败: $errorMessage")))
}
}
})
}
override fun onError(errorCode: Int, errorMessage: String) {
handler.post {
Log.e(TAG, "${actionName}失败: $errorMessage")
callback(Result.failure(Exception("${actionName}失败: $errorMessage")))
}
callback(Result.failure(Exception("$actionName 失败: $errorMessage")))
}
})
}

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

@ -203,22 +203,6 @@ class QqMusicPlugin: FlutterPlugin, MethodCallHandler, ActivityAware {
)
}
}
"getPlayTime" -> {
qqMusicSingleton.getPlayTime { kotlinResult ->
kotlinResult.fold(
onSuccess = { playTimeInfo ->
result.success(mapOf(
"success" to true,
"totalTime" to playTimeInfo.totalTime,
"currentTime" to playTimeInfo.currentTime
))
},
onFailure = { error ->
result.error("GET_TIME_FAILED", error.message, null)
}
)
}
}
"syncCurrentPlayInfo" -> {
qqMusicSingleton.syncCurrentPlayInfo { kotlinResult ->
kotlinResult.fold(

Loading…
Cancel
Save