From 3c94ac0466dd3a614bfbc685b1ab83a7aa90a224 Mon Sep 17 00:00:00 2001 From: liwei1dao Date: Tue, 5 Aug 2025 20:36:12 +0800 Subject: [PATCH] =?UTF-8?q?=E4=B8=8A=E4=BC=A0qq=E9=9F=B3=E4=B9=90=E6=9C=8D?= =?UTF-8?q?=E5=8A=A1=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- android/app/sign/DeepSound.properties | 4 -- .../qqmusic_playlist_controller.dart | 36 +++++++++++----- .../qq_music/QQMusicLoginManager.kt | 2 +- .../qq_music/QQMusicManager.kt | 25 +++++++++-- .../qq_music/QQMusicSingleton.kt | 43 ++++++++++++++++++- .../qq_music/util/QPlayBindHelper.kt | 43 ++++++++++++++++++- 6 files changed, 130 insertions(+), 23 deletions(-) delete mode 100644 android/app/sign/DeepSound.properties diff --git a/android/app/sign/DeepSound.properties b/android/app/sign/DeepSound.properties deleted file mode 100644 index 96bb7e16a..000000000 --- a/android/app/sign/DeepSound.properties +++ /dev/null @@ -1,4 +0,0 @@ -storePassword=13071376716 -keyPassword=13071376716 -keyAlias=DeepSound -storeFile=sign/DeepSound.keystore \ No newline at end of file diff --git a/lib/modules/qqmusic/controllers/qqmusic_playlist_controller.dart b/lib/modules/qqmusic/controllers/qqmusic_playlist_controller.dart index 0c0733191..32f0fc179 100644 --- a/lib/modules/qqmusic/controllers/qqmusic_playlist_controller.dart +++ b/lib/modules/qqmusic/controllers/qqmusic_playlist_controller.dart @@ -1,3 +1,5 @@ +import 'package:flutter/scheduler.dart'; +import 'package:flutter/widgets.dart'; import 'package:get/get.dart'; import '../../../data/models/song_model.dart'; import '../../../data/services/qq_musoc.dart'; @@ -22,6 +24,16 @@ class QQMusicPlaylistController extends GetxController { void onInit() { super.onInit(); + // 使用 WidgetsBinding.instance.addPostFrameCallback 延迟执行状态更新 + WidgetsBinding.instance.addPostFrameCallback((_) { + _initializePlaylist(); + }); + + print('🎵 [QQMusicPlaylistController] 控制器初始化完成'); + } + + /// 初始化播放列表 - 延迟执行避免构建期间状态更新 + void _initializePlaylist() { // 从路由参数获取播放列表 final arguments = Get.arguments; if (arguments != null && arguments['playlist'] != null) { @@ -76,11 +88,9 @@ class QQMusicPlaylistController extends GetxController { // 界面初始化时同步播放状态和进度 _syncInitialState(); - - print('🎵 [QQMusicPlaylistController] 控制器初始化完成'); } - /// 同步初始播放状态 + /// 同步初始播放状态 - 移除 update() 调用 Future _syncInitialState() async { try { Logger.d('QQMusicPlaylist', '开始同步初始播放状态'); @@ -94,8 +104,8 @@ class QQMusicPlaylistController extends GetxController { _qqMusicService.startPlaybackStateMonitor(); } - // 触发UI更新 - update(); + // 移除这行,避免在构建期间调用 update() + // update(); Logger.d('QQMusicPlaylist', '初始状态同步完成'); } catch (e) { @@ -103,6 +113,16 @@ class QQMusicPlaylistController extends GetxController { } } + /// 音乐状态变化回调 - 使用 SchedulerBinding 延迟更新 + void _onMusicStateChanged() { + // 使用 SchedulerBinding 确保在构建完成后再更新 + SchedulerBinding.instance.addPostFrameCallback((_) { + if (!isClosed) { + update(); + } + }); + } + @override void onClose() { // 移除状态监听器 @@ -110,12 +130,6 @@ class QQMusicPlaylistController extends GetxController { super.onClose(); } - /// 音乐状态变化回调 - void _onMusicStateChanged() { - // 触发UI更新 - update(); - } - /// 播放歌曲 Future playSong(SongModel song, {List? songList}) async { try { 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 05fe5c51d..f077819cd 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 @@ -76,7 +76,7 @@ class QQMusicLoginManager(private val activity: Activity) { } else { Log.e(TAG, "QQ音乐服务绑定失败") - callback.onError("BIND_FAILED", "绑定QQ音乐服务失败,请确保已安装QQ音乐") + callback.onError("APP_NOT_INSTALLED", "请先安装QQ音乐App才能使用音乐功能") } } } 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 7635c1006..0bfb00a28 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 @@ -5,6 +5,7 @@ import android.content.ComponentName import android.content.Context import android.content.Intent import android.content.ServiceConnection +import android.content.pm.PackageManager import android.os.Bundle import android.os.IBinder import android.util.Log @@ -97,7 +98,7 @@ class QQMusicManager(private val activity: Activity) { private fun bindQQMusicApiService() { 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 { @@ -154,7 +155,7 @@ class QQMusicManager(private val activity: Activity) { callback: SearchCallback ) { Log.d(TAG, "searchSongs: keyword=$keyword, searchType=$searchType") - + if (!isBindQQMusicService || qqmusicApi == null) { Log.e(TAG, "QQ音乐服务未连接") callback.onError(-1, "QQ音乐服务未连接") @@ -275,6 +276,7 @@ class QQMusicManager(private val activity: Activity) { index: Int = 0, callback: PlayCallback ) { + if (!isBindQQMusicService || qqmusicApi == null) { callback.onError(-1, "QQ音乐服务未连接") return @@ -303,6 +305,7 @@ class QQMusicManager(private val activity: Activity) { * 播放音乐 */ fun playMusic(callback: PlayCallback) { + if (!isBindQQMusicService || qqmusicApi == null) { callback.onError(-1, "QQ音乐服务未连接") return @@ -614,10 +617,24 @@ class QQMusicManager(private val activity: Activity) { if (isBindQQMusicService) { activity.unbindService(serviceConnection) isBindQQMusicService = false + Log.d(TAG, "QQ音乐服务已解绑") } } catch (e: Exception) { - Log.e(TAG, "清理资源异常", e) + Log.e(TAG, "解绑QQ音乐服务失败", e) + } + } + + + + /** + * 获取当前平台对应的QQ音乐包名 + */ + private fun getQQMusicPackageName(): String { + return when (Config.BIND_PLATFORM) { + CommonCmd.AIDL_PLATFORM_TYPE_PHONE -> "com.tencent.qqmusic" + CommonCmd.AIDL_PLATFORM_TYPE_CAR -> "com.tencent.qqmusiccar" + CommonCmd.AIDL_PLATFORM_TYPE_TV -> "com.tencent.qqmusictv" + else -> "com.tencent.qqmusic" } - qqmusicApi = null } } \ No newline at end of file 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 54af8bf91..be5ce6ae3 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 @@ -3,6 +3,7 @@ package com.yunqiinnovation.qq_music import android.app.Activity import android.content.Context import android.content.SharedPreferences +import android.content.pm.PackageManager import android.os.Handler import android.os.Looper import android.util.Log @@ -56,7 +57,32 @@ class QQMusicSingleton private constructor() { loadSavedLoginInfo() Log.d(TAG, "QQ音乐单例初始化完成") } - + /** + * 检查QQ音乐App是否已安装 + */ + private fun isQQMusicInstalled(): Boolean { + val packageName = when (Config.BIND_PLATFORM) { + CommonCmd.AIDL_PLATFORM_TYPE_PHONE -> "com.tencent.qqmusic" + CommonCmd.AIDL_PLATFORM_TYPE_CAR -> "com.tencent.qqmusiccar" + CommonCmd.AIDL_PLATFORM_TYPE_TV -> "com.tencent.qqmusictv" + else -> { + Log.e(TAG, "不支持的平台类型: ${Config.BIND_PLATFORM}") + return false + } + } + + return try { + this.activity?.packageManager?.getPackageInfo(packageName, 0) + Log.d(TAG, "QQ音乐app已安装: $packageName") + true + } catch (e: PackageManager.NameNotFoundException) { + Log.w(TAG, "QQ音乐app未安装: $packageName") + false + } catch (e: Exception) { + Log.e(TAG, "检查QQ音乐app安装状态失败", e) + false + } + } /** * 检查是否已登录且未过期 */ @@ -88,6 +114,11 @@ class QQMusicSingleton private constructor() { * 登录接口 */ fun login(callback: (Result) -> Unit) { + if (!isQQMusicInstalled()){ + callback(Result.failure(Exception("未安装QQ音乐软件,请先安装QQ音乐软件"))) + return + } + // 先检查是否已经登录且未过期 if (isLoggedIn()) { Log.d(TAG, "用户已登录且未过期,直接返回登录信息") @@ -140,6 +171,10 @@ 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, 0, callback) } @@ -264,12 +299,16 @@ class QQMusicSingleton private constructor() { index: Int = 0, 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 + } ensureMusicManager(currentActivity) musicManager?.playSongs(songMids, index, object : QQMusicManager.PlayCallback { override fun onSuccess() { diff --git a/local_plugins/qq_music/android/src/main/kotlin/com/yunqiinnovation/qq_music/util/QPlayBindHelper.kt b/local_plugins/qq_music/android/src/main/kotlin/com/yunqiinnovation/qq_music/util/QPlayBindHelper.kt index 2c2b83437..85c319ee4 100644 --- a/local_plugins/qq_music/android/src/main/kotlin/com/yunqiinnovation/qq_music/util/QPlayBindHelper.kt +++ b/local_plugins/qq_music/android/src/main/kotlin/com/yunqiinnovation/qq_music/util/QPlayBindHelper.kt @@ -4,6 +4,7 @@ import android.content.ComponentName import android.content.Context import android.content.Intent import android.content.ServiceConnection +import android.content.pm.PackageManager import android.os.Handler import android.os.IBinder import android.os.Looper @@ -12,6 +13,7 @@ import android.widget.Toast import com.tencent.qqmusic.third.api.contract.CommonCmd import com.tencent.qqmusic.third.api.contract.CommonCmd.AIDL_PLATFORM_TYPE_PHONE import com.tencent.qqmusic.third.api.contract.IQQMusicApi +import com.yunqiinnovation.qq_music.Config class QPlayBindHelper(private val context: Context, private val bindPlatform: String = AIDL_PLATFORM_TYPE_PHONE) { companion object { @@ -104,11 +106,50 @@ class QPlayBindHelper(private val context: Context, private val bindPlatform: St bindQQMusic(callback) } + /** + * 检查QQ音乐App是否已安装 + */ + private fun isQQMusicInstalled(): Boolean { + return try { + val packageName = getQQMusicPackageName() + context.packageManager.getPackageInfo(packageName, PackageManager.GET_ACTIVITIES) + true + } catch (e: PackageManager.NameNotFoundException) { + Log.w(TAG, "QQ音乐App未安装: ${e.message}") + false + } + } + + /** + * 获取QQ音乐包名 + */ + private fun getQQMusicPackageName(): String { + return when (Config.BIND_PLATFORM) { + CommonCmd.AIDL_PLATFORM_TYPE_PHONE -> "com.tencent.qqmusic" + CommonCmd.AIDL_PLATFORM_TYPE_CAR -> "com.tencent.qqmusiccar" + CommonCmd.AIDL_PLATFORM_TYPE_TV -> "com.tencent.qqmusictv" + else -> "com.tencent.qqmusic" + } + } + fun ensureQQMusicBindByStartProcess(isStartProcess: Boolean = true, callback: ((Boolean) -> Unit)? = null) { + // 首先检查QQ音乐是否已安装 + if (!isQQMusicInstalled()) { + Log.e(TAG, "QQ音乐App未安装,无法绑定服务") + callback?.invoke(false) + return + } + bindQQMusic({ succeed -> if (!succeed) { if (isStartProcess) { - CommonCmd.startQQMusicProcess(context, context.packageName) + try { + CommonCmd.startQQMusicProcess(context, context.packageName) + } catch (e: Exception) { + Log.e(TAG, "启动QQ音乐进程失败: ${e.message}") + callback?.invoke(false) + return@bindQQMusic + } } handler.postDelayed({ ensureQQMusicBindByStartProcess(false, callback)