From 27e4b73202eb191751f4166b393ee3aee13fc1f5 Mon Sep 17 00:00:00 2001 From: liwei1dao Date: Thu, 4 Sep 2025 12:13:22 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96qq=E9=9F=B3=E4=B9=90=E6=9C=8D?= =?UTF-8?q?=E5=8A=A1=E4=BB=A3=E7=A0=81=EF=BC=8C=E4=BF=AE=E5=A4=8D=E6=90=9C?= =?UTF-8?q?=E7=B4=A2=E4=B8=8D=E4=B8=BB=E5=8A=A8=E6=92=AD=E6=94=BE=E7=9A=84?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../chat_api/QQMusicSystemFunctionHandler.kt | 120 +---- .../qq_music/QQMusicLoginManager.kt | 35 +- .../qq_music/QQMusicManager.kt | 106 +++-- .../qq_music/QQMusicSingleton.kt | 438 ++++++++---------- .../yunqiinnovation/qq_music/QqMusicPlugin.kt | 16 - 5 files changed, 280 insertions(+), 435 deletions(-) diff --git a/local_plugins/chat_api/android/src/main/kotlin/com/yunqiinnovation/chat_api/QQMusicSystemFunctionHandler.kt b/local_plugins/chat_api/android/src/main/kotlin/com/yunqiinnovation/chat_api/QQMusicSystemFunctionHandler.kt index b500773cf..e8e70f9a7 100644 --- a/local_plugins/chat_api/android/src/main/kotlin/com/yunqiinnovation/chat_api/QQMusicSystemFunctionHandler.kt +++ b/local_plugins/chat_api/android/src/main/kotlin/com/yunqiinnovation/chat_api/QQMusicSystemFunctionHandler.kt @@ -48,41 +48,7 @@ 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(), -// "required" to emptyList() -// ), -// QQMusicPlayHandler(context) -// ) - + client.registerLocalFunction( "qqmusic_pause", "暂停QQ音乐", @@ -137,40 +103,7 @@ class QQMusicSystemFunctionHandler(private val context: Context? = null) { ), QQMusicPreviousHandler(context) ) - - // QQ音乐状态查询 - client.registerLocalFunction( - "qqmusic_get_playback_state", - "获取QQ音乐播放状态", - mapOf( - "type" to "object", - "properties" to emptyMap(), - "required" to emptyList() - ), - QQMusicGetPlaybackStateHandler(context) - ) - - client.registerLocalFunction( - "qqmusic_get_current_song", - "获取QQ音乐当前播放歌曲信息", - mapOf( - "type" to "object", - "properties" to emptyMap(), - "required" to emptyList() - ), - QQMusicGetCurrentSongHandler(context) - ) - - client.registerLocalFunction( - "qqmusic_get_play_time", - "获取QQ音乐播放时间信息", - mapOf( - "type" to "object", - "properties" to emptyMap(), - "required" to emptyList() - ), - 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 { - 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 { 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 { - 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}\"}" - } - } -} \ No newline at end of file diff --git a/local_plugins/qq_music/android/src/main/kotlin/com/yunqiinnovation/qq_music/QQMusicLoginManager.kt b/local_plugins/qq_music/android/src/main/kotlin/com/yunqiinnovation/qq_music/QQMusicLoginManager.kt index 4674fca8f..41183820b 100644 --- a/local_plugins/qq_music/android/src/main/kotlin/com/yunqiinnovation/qq_music/QQMusicLoginManager.kt +++ b/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}") } diff --git a/local_plugins/qq_music/android/src/main/kotlin/com/yunqiinnovation/qq_music/QQMusicManager.kt b/local_plugins/qq_music/android/src/main/kotlin/com/yunqiinnovation/qq_music/QQMusicManager.kt index 822a6cc06..414d46856 100644 --- a/local_plugins/qq_music/android/src/main/kotlin/com/yunqiinnovation/qq_music/QQMusicManager.kt +++ b/local_plugins/qq_music/android/src/main/kotlin/com/yunqiinnovation/qq_music/QQMusicManager.kt @@ -39,38 +39,27 @@ class QQMusicManager(private val context: Context) { fun onSuccess(data: Map) 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,9 +86,9 @@ 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) { CommonCmd.AIDL_PLATFORM_TYPE_PHONE -> { Intent("com.tencent.qqmusic.third.api.QQMusicApiService").apply { @@ -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,22 +115,71 @@ 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) { Log.e(TAG, "绑定QQ音乐服务失败,尝试启动QQ音乐进程") // 尝试启动QQ音乐进程 CommonCmd.startQQMusicProcess(context, context.packageName) - + // 延迟重试绑定 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音乐服务已解绑") } diff --git a/local_plugins/qq_music/android/src/main/kotlin/com/yunqiinnovation/qq_music/QQMusicSingleton.kt b/local_plugins/qq_music/android/src/main/kotlin/com/yunqiinnovation/qq_music/QQMusicSingleton.kt index 53ff7b3e8..9b9762381 100644 --- a/local_plugins/qq_music/android/src/main/kotlin/com/yunqiinnovation/qq_music/QQMusicSingleton.kt +++ b/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,12 +21,7 @@ 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 - } + return loginManager != null && loginManager!!.isLogined } - - /** - * 获取当前登录信息 - */ - fun getCurrentLoginInfo(): LoginResult? { - return if (isLoggedIn()) currentLoginResult else null - } - + /** * 登录接口 */ - fun login(callback: (Result) -> Unit) { + fun login(callback: (Result) -> 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,129 +187,12 @@ class QQMusicSingleton private constructor() { searchType: Int = Data.SearchType.SEARCH_TYPE_SONG, callback: (Result>>) -> 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>>) -> 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) - } - } - - /** - * 执行带超时的搜索操作 - */ - private fun performSearchWithTimeout( - keyword: String, - searchType: Int, - retryCount: Int, - callback: (Result>>) -> 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>) { - 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"))) - } - } - } - } - }) + executeSearchbackAction("搜索歌曲",0,2) { musicManager, searchCallback -> + musicManager.searchSongs(keyword,searchType,searchCallback) + }(callback) } + /** * 播放歌曲列表(带自动登录检查) */ @@ -321,8 +201,8 @@ class QQMusicSingleton private constructor() { index: Int = 0, callback: (Result) -> 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) { - 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) { - 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) { - 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) { - 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) { - executePlaybackAction("上一首") { musicManager, playCallback -> + executePlaybackAction("上一首",0,0) { musicManager, playCallback -> musicManager.skipToPrevious(playCallback) }(callback) } @@ -443,60 +324,20 @@ class QQMusicSingleton private constructor() { /** * 获取播放时间 */ - fun getPlayTime(callback: (Result) -> 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) { - 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)) - } - } - - override fun onError(errorCode: Int, errorMessage: String) { - handler.post { - Log.e(TAG, "获取播放时间失败: $errorMessage") - callback(Result.failure(Exception("获取播放时间失败: $errorMessage"))) - } - } - }) + fun getPlayTime(callback: (Result>) -> Unit) { + executeInfoAction("获取播放时间") { musicManager, infoCallback -> + musicManager.getPlayTime(infoCallback) + }(callback) + } /** * 同步当前播放信息 - 统一接口 */ fun syncCurrentPlayInfo(callback: (Result>) -> 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) { - 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>>) -> 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>) { + 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 { return lambda@{ callback -> @@ -583,30 +491,42 @@ class QQMusicSingleton private constructor() { callback(Result.failure(Exception("Activity not available"))) return@lambda } - - ensureMusicManager(currentActivity) - action(musicManager!!, object : QQMusicManager.PlayCallback { - override fun onSuccess() { - handler.post { - Log.d(TAG, "${actionName}成功") - callback(Result.success(Unit)) - } - } + 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)) + } + } + + 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>) -> 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) { - 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) { + 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"))) } }) } diff --git a/local_plugins/qq_music/android/src/main/kotlin/com/yunqiinnovation/qq_music/QqMusicPlugin.kt b/local_plugins/qq_music/android/src/main/kotlin/com/yunqiinnovation/qq_music/QqMusicPlugin.kt index 62f8c40a2..726bcd451 100644 --- a/local_plugins/qq_music/android/src/main/kotlin/com/yunqiinnovation/qq_music/QqMusicPlugin.kt +++ b/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(