From 1e8c0278f577c6fb4dca3dbcfccc54df838dd4f5 Mon Sep 17 00:00:00 2001 From: liwei1dao Date: Fri, 15 Aug 2025 15:50:24 +0800 Subject: [PATCH 1/2] =?UTF-8?q?=E4=B8=8A=E4=BC=A0=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/data/services/qq_musoc.dart | 9 ++- .../qq_music/QQMusicManager.kt | 2 +- .../qq_music/QQMusicSingleton.kt | 57 ++++++++++++++++--- 3 files changed, 58 insertions(+), 10 deletions(-) diff --git a/lib/data/services/qq_musoc.dart b/lib/data/services/qq_musoc.dart index 13d16fed3..bed5c7dad 100644 --- a/lib/data/services/qq_musoc.dart +++ b/lib/data/services/qq_musoc.dart @@ -1,4 +1,5 @@ import 'dart:async'; +import 'dart:ffi'; import 'package:get/get.dart'; import 'package:qq_music/qq_music.dart'; import '../models/song_model.dart'; @@ -36,7 +37,7 @@ class QqMusocService extends GetxService { if (result['success'] == true) { print('QQ音乐自动登录成功: ${result['openId']}'); Future.delayed(Duration(milliseconds: 1000), () { - syncCurrentPlayInfo(); + syncCurrentPlayInfo(isFrest: true); }); } else { print('QQ音乐自动登录失败: ${result['error']}'); @@ -420,7 +421,8 @@ class QqMusocService extends GetxService { } /// 同步当前播放信息 - 统一接口 - Future> syncCurrentPlayInfo() async { + Future> syncCurrentPlayInfo( + {bool isFrest = false}) async { try { _stateMonitorTimer?.cancel(); //先关闭计时器 final result = await _qqMusic.syncCurrentPlayInfo(); @@ -468,6 +470,9 @@ class QqMusocService extends GetxService { if (newIsPlaying) { //正在播放 startPlaybackStateMonitor(); + } else { + stopPlaybackStateMonitor(); + currentSong.value = null; } // 通知所有监听器 _notifyListeners(); 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 edcf3c365..1e4f8a5c1 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 @@ -95,7 +95,7 @@ class QQMusicManager(private val activity: Activity) { } } - private fun bindQQMusicApiService() { + fun bindQQMusicApiService() { Log.d(TAG, "开始绑定QQ音乐服务,平台类型: ${Config.BIND_PLATFORM}") val intent = when (Config.BIND_PLATFORM) { 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 373293c23..0ca0d0d43 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 @@ -311,23 +311,63 @@ class QQMusicSingleton private constructor() { } /** - * 播放歌曲列表 + * 播放歌曲列表(带自动登录检查) */ fun playSongs( songMids: List, index: Int = 0, callback: (Result) -> Unit ) { - + if (!isQQMusicInstalled()){ + callback(Result.failure(Exception("未安装QQ音乐软件,请先安装QQ音乐软件"))) + return + } + playWithRetry(songMids, index, callback) + } + + /** + * 带自动登录检查的播放实现 + */ + private fun playWithRetry( + songMids: List, + index: Int, + callback: (Result) -> Unit + ) { val currentActivity = activity if (currentActivity == null) { callback(Result.failure(Exception("Activity not available"))) return } - if (!isQQMusicInstalled()){ - callback(Result.failure(Exception("未安装QQ音乐软件,请先安装QQ音乐软件"))) - return + + // 检查登录状态 + if (!isLoggedIn()) { + Log.d(TAG, "播放前检测到未登录,开始自动登录") + login { loginResult -> + if (loginResult.isSuccess) { + Log.d(TAG, "自动登录成功,等待QQ音乐服务连接...") + handler.postDelayed({ + Log.d(TAG, "等待完成,开始播放") + performPlaySongs(songMids, index, callback) + }, LOGIN_WAIT_DELAY_MS) + } else { + callback(Result.failure(Exception("自动登录失败: ${loginResult.exceptionOrNull()?.message}"))) + } + } + } else { + performPlaySongs(songMids, index, callback) } + } + + /** + * 执行播放歌曲列表操作 + */ + private fun performPlaySongs( + songMids: List, + index: Int, + callback: (Result) -> Unit + ) { + val currentActivity = activity ?: return + ensureMusicManager(currentActivity) musicManager?.playSongs(songMids, index, object : QQMusicManager.PlayCallback { override fun onSuccess() { @@ -340,10 +380,13 @@ class QQMusicSingleton private constructor() { override fun onError(errorCode: Int, errorMessage: String) { handler.post { Log.e(TAG, "播放失败: $errorCode $errorMessage") - if (errorCode != 1030) { + if (errorCode == -1){ + musicManager?.bindQQMusicApiService() callback(Result.failure(Exception("播放失败: $errorMessage"))) - }else{ + } else if (errorCode == 1030) { callback(Result.success(Unit)) + }else{ + callback(Result.failure(Exception("播放失败: $errorMessage"))) } } } From fb626c0acf3ba8a9ef4b7179d8327b061be5cf6c Mon Sep 17 00:00:00 2001 From: liwei1dao Date: Fri, 15 Aug 2025 17:32:13 +0800 Subject: [PATCH 2/2] =?UTF-8?q?iOS=20=E9=9F=B3=E4=B9=90=E6=8E=88=E6=9D=83?= =?UTF-8?q?=E8=BF=9E=E6=8E=A5=E5=A4=9A=E6=AC=A1=E9=97=AE=E9=A2=98=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Sources/qq_music/QPlayAutoManager.swift | 33 ++++++++++++------- 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/local_plugins/qq_music/ios/qq_music/Sources/qq_music/QPlayAutoManager.swift b/local_plugins/qq_music/ios/qq_music/Sources/qq_music/QPlayAutoManager.swift index 57aa637a8..4c0f5bb0a 100644 --- a/local_plugins/qq_music/ios/qq_music/Sources/qq_music/QPlayAutoManager.swift +++ b/local_plugins/qq_music/ios/qq_music/Sources/qq_music/QPlayAutoManager.swift @@ -239,7 +239,12 @@ import QPlayAutoSDK guard retryCount > 0 else { print("QPlayAutoManager: ❌ 连接失败,所有重试次数已用完") print("QPlayAutoManager: 最终状态 - isConnected: \(isConnected), isLoginOK: \(isLoginOK)") - notifyLoginCompletion(false) + + // 只有在所有重试都失败且确实有待处理回调时才清理 + if !loginCompletionHandlers.isEmpty { + print("QPlayAutoManager: 清理登录回调队列") + notifyLoginCompletion(false) + } return } @@ -248,7 +253,7 @@ import QPlayAutoSDK QPlayAutoSDK.connectAndForceLogin(forceLogin) // If connection fails due to socket error, retry after cleanup - DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) { + DispatchQueue.main.asyncAfter(deadline: .now() + 3.0) { let endTime = Date() let duration = endTime.timeIntervalSince(startTime) @@ -404,9 +409,9 @@ import QPlayAutoSDK // 强制登录,会跳转到QQ音乐 connect(forceLogin: true) - // 设置超时检查 - DispatchQueue.main.asyncAfter(deadline: .now() + 10.0) { [weak self] in - self?.checkLoginTimeout() + // 设置超时监控(仅记录,不清理回调) + DispatchQueue.main.asyncAfter(deadline: .now() + 30.0) { [weak self] in + self?.logLoginTimeout() } } @@ -422,16 +427,16 @@ import QPlayAutoSDK return currentTime.timeIntervalSince(loginTime) <= Self.TOKEN_EXPIRE_TIME } - private func checkLoginTimeout() { - print("QPlayAutoManager: ⏰ 检查登录超时") + private func logLoginTimeout() { + print("QPlayAutoManager: ⏰ 登录超时监控") print("QPlayAutoManager: 当前状态 - 队列长度: \(loginCompletionHandlers.count), isLoginOK: \(isLoginOK)") + print("QPlayAutoManager: 连接状态 - isConnected: \(isConnected), isConnecting: \(isConnecting)") if !loginCompletionHandlers.isEmpty && !isLoginOK { - print("QPlayAutoManager: ❌ 登录超时,清理回调队列") - print("QPlayAutoManager: 超时时状态 - isConnected: \(isConnected), isQQMusicInstalled: \(isQQMusicInstalled)") - notifyLoginCompletion(false) + print("QPlayAutoManager: ⚠️ 登录可能超时,但保留回调等待最终结果") + print("QPlayAutoManager: 如果确实超时,将由重试机制或连接失败回调处理") } else if isLoginOK { - print("QPlayAutoManager: ✅ 登录已完成,无需超时处理") + print("QPlayAutoManager: ✅ 登录已完成") } else { print("QPlayAutoManager: 无待处理的登录请求") } @@ -811,13 +816,17 @@ extension QPlayAutoManager: QPlayAutoSDKDelegate { print("QPlayAutoManager: Login state changed to \(isLoginOK)") _isLoginOK = isLoginOK - // 登录成功时保存token + // 登录成功时保存token并通知回调 if isLoginOK { saveLoginToken() + print("QPlayAutoManager: ✅ 登录成功,通知所有等待的回调") notifyLoginCompletion(true) } else { // 登录失败时清除可能无效的token clearStoredToken() + print("QPlayAutoManager: ❌ 登录失败,但不立即清理回调(等待重试或最终失败)") + // 注意:这里不立即调用 notifyLoginCompletion(false) + // 让重试机制来决定是否最终失败 } // 通知所有代理