From abd0941701c71ced024a3f8602dafee9fb6286d1 Mon Sep 17 00:00:00 2001 From: liwei1dao Date: Mon, 16 Jun 2025 15:56:03 +0800 Subject: [PATCH] =?UTF-8?q?=E4=B8=8A=E4=BC=A0=E6=92=AD=E6=94=BE=E6=8E=A7?= =?UTF-8?q?=E5=88=B6=E5=99=A8=E6=8E=A5=E5=8F=A3=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../chat_api/SystemFunctionHandler.kt | 24 +++++- .../music_service/MusicService.kt | 74 +++++++++++++++++-- .../music_service/MusicServicePlugin.swift | 32 ++++++++ 3 files changed, 120 insertions(+), 10 deletions(-) diff --git a/local_plugins/chat_api/android/src/main/kotlin/com/yunqiinnovation/chat_api/SystemFunctionHandler.kt b/local_plugins/chat_api/android/src/main/kotlin/com/yunqiinnovation/chat_api/SystemFunctionHandler.kt index 058cb0876..655408e71 100644 --- a/local_plugins/chat_api/android/src/main/kotlin/com/yunqiinnovation/chat_api/SystemFunctionHandler.kt +++ b/local_plugins/chat_api/android/src/main/kotlin/com/yunqiinnovation/chat_api/SystemFunctionHandler.kt @@ -8,7 +8,9 @@ import android.net.Uri import android.os.Build import android.provider.CalendarContract import android.telephony.SmsManager +import android.util.Log import androidx.core.content.ContextCompat +import androidx.core.content.ContextCompat.RECEIVER_NOT_EXPORTED import java.text.SimpleDateFormat import java.util.* @@ -393,7 +395,10 @@ private class GetCurrentLocationHandler(private val context: Context?) : Functio private class MediaPlayHandler(private val context: Context?) : FunctionHandler { override suspend fun handle(arguments: Map): String { // 发送媒体播放广播 - context?.sendBroadcast(Intent("com.yunqiinnovation.deepsound.MEDIA_PLAY")) + val intent = Intent("com.yunqiinnovation.music_service.MEDIA_PLAY").apply { + setPackage(context?.packageName) // 设置包名使其成为显式 Intent + } + context?.sendBroadcast(intent) return "{\"result\": \"已开始播放媒体\"}" } } @@ -403,8 +408,12 @@ private class MediaPlayHandler(private val context: Context?) : FunctionHandler */ private class MediaPauseHandler(private val context: Context?) : FunctionHandler { override suspend fun handle(arguments: Map): String { + Log.d("MediaPauseHandler", "📤 正在发送广播 context = $context") // 发送媒体暂停广播 - context?.sendBroadcast(Intent("com.yunqiinnovation.deepsound.MEDIA_PAUSE")) + val intent = Intent("com.yunqiinnovation.music_service.MEDIA_PAUSE").apply { + setPackage(context?.packageName) // 设置包名使其成为显式 Intent + } + context?.sendBroadcast(intent) return "{\"result\": \"已暂停媒体播放\"}" } } @@ -415,7 +424,11 @@ private class MediaPauseHandler(private val context: Context?) : FunctionHandler private class MediaPreviousHandler(private val context: Context?) : FunctionHandler { override suspend fun handle(arguments: Map): String { // 发送切换上一首广播 - context?.sendBroadcast(Intent("com.yunqiinnovation.deepsound.MEDIA_PREVIOUS")) +// context?.applicationContext?.sendBroadcast(Intent("com.yunqiinnovation.music_service.MEDIA_PREVIOUS")) + val intent = Intent("com.yunqiinnovation.music_service.MEDIA_PREVIOUS").apply { + setPackage(context?.packageName) // 设置包名使其成为显式 Intent + } + context?.sendBroadcast(intent) return "{\"result\": \"已切换到上一首\"}" } } @@ -426,7 +439,10 @@ private class MediaPreviousHandler(private val context: Context?) : FunctionHand private class MediaNextHandler(private val context: Context?) : FunctionHandler { override suspend fun handle(arguments: Map): String { // 发送切换下一首广播 - context?.sendBroadcast(Intent("com.yunqiinnovation.deepsound.MEDIA_NEXT")) +// context?.applicationContext?.sendBroadcast(Intent("com.yunqiinnovation.music_service.MEDIA_NEXT")) + val intent = Intent("com.yunqiinnovation.music_service.MEDIA_NEXT").apply { + setPackage(context?.packageName) // 设置包名使其成为显式 Intent + } return "{\"result\": \"已切换到下一首\"}" } } diff --git a/local_plugins/music_service/android/src/main/kotlin/com/yunqiinnovation/music_service/MusicService.kt b/local_plugins/music_service/android/src/main/kotlin/com/yunqiinnovation/music_service/MusicService.kt index cd9f61791..16104dacb 100644 --- a/local_plugins/music_service/android/src/main/kotlin/com/yunqiinnovation/music_service/MusicService.kt +++ b/local_plugins/music_service/android/src/main/kotlin/com/yunqiinnovation/music_service/MusicService.kt @@ -4,8 +4,10 @@ import android.app.Notification import android.app.NotificationChannel import android.app.NotificationManager import android.app.PendingIntent +import android.content.BroadcastReceiver import android.content.Context import android.content.Intent +import android.content.IntentFilter import android.graphics.BitmapFactory import android.media.AudioManager import android.media.MediaPlayer @@ -41,7 +43,7 @@ class MusicService : MediaBrowserServiceCompat() { fun isPlaying() = currentStatus fun getCurrentUrl(): String? = currentUrlInternal } - + private var isReceiverRegistered = false private lateinit var mediaSession: MediaSessionCompat private lateinit var audioManager: AudioManager private var mediaPlayer: MediaPlayer? = null @@ -52,6 +54,22 @@ class MusicService : MediaBrowserServiceCompat() { setupMediaSession() startForeground(NOTIFICATION_ID, createNotification("等待播放","DeepSound","")) audioManager = getSystemService(Context.AUDIO_SERVICE) as AudioManager + + // 注册广播监听器 + val filter = IntentFilter().apply { + addAction("com.yunqiinnovation.music_service.MEDIA_PLAY") + addAction("com.yunqiinnovation.music_service.MEDIA_PAUSE") + addAction("com.yunqiinnovation.music_service.MEDIA_PREVIOUS") + addAction("com.yunqiinnovation.music_service.MEDIA_NEXT") + } + + // Android 14+ 需要指定 flag + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + registerReceiver(controlReceiver, filter, Context.RECEIVER_NOT_EXPORTED) + } else { + registerReceiver(controlReceiver, filter) + } + isReceiverRegistered = true Log.i(TAG, "MediaService 启动完成") } @@ -100,6 +118,32 @@ class MusicService : MediaBrowserServiceCompat() { return START_STICKY } + + private val controlReceiver = object : BroadcastReceiver() { + override fun onReceive(context: Context?, intent: Intent?) { + Log.i(TAG, "接受到通知事件 ${intent?.action}") + when (intent?.action) { + "com.yunqiinnovation.music_service.MEDIA_PAUSE" -> { + Log.i(TAG, "收到 MEDIA_PAUSE 广播") + pause() + } + "com.yunqiinnovation.music_service.MEDIA_PLAY" -> { + Log.i(TAG, "收到 MEDIA_RESUME 广播") + resume() + } + "com.yunqiinnovation.music_service.MEDIA_PREVIOUS" -> { + Log.i(TAG, "收到 MEDIA_RESUME 广播") + playPrevious() + } + "com.yunqiinnovation.music_service.MEDIA_NEXT" -> { + Log.i(TAG, "收到 MEDIA_RESUME 广播") + playNext() + } + // 你也可以扩展支持更多指令 + } + } + } + private fun setupMediaSession() { mediaSession = MediaSessionCompat(this, "MusicMediaSession").apply { setFlags( @@ -190,19 +234,33 @@ class MusicService : MediaBrowserServiceCompat() { return builder.build() } - fun mediaButtonPendingIntent(action: Long): PendingIntent { - val intent = Intent(this, MusicService::class.java).apply { - this.action = Intent.ACTION_MEDIA_BUTTON - putExtra(Intent.EXTRA_KEY_EVENT, KeyEvent(KeyEvent.ACTION_DOWN, action.toKeyCode())) + val keyEvent = KeyEvent(KeyEvent.ACTION_DOWN, action.toKeyCode()) + val intent = Intent(Intent.ACTION_MEDIA_BUTTON).apply { + setPackage(packageName) + putExtra(Intent.EXTRA_KEY_EVENT, keyEvent) } + val flags = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE } else { PendingIntent.FLAG_UPDATE_CURRENT } - return PendingIntent.getService(this, action.toInt(), intent, flags) + + return PendingIntent.getBroadcast(this, action.toInt(), intent, flags) } +// fun mediaButtonPendingIntent(action: Long): PendingIntent { +// val intent = Intent(this, MusicService::class.java).apply { +// this.action = Intent.ACTION_MEDIA_BUTTON +// putExtra(Intent.EXTRA_KEY_EVENT, KeyEvent(KeyEvent.ACTION_DOWN, action.toKeyCode())) +// } +// val flags = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { +// PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE +// } else { +// PendingIntent.FLAG_UPDATE_CURRENT +// } +// return PendingIntent.getService(this, action.toInt(), intent, flags) +// } // 转换 PlaybackStateCompat.ACTION 到 KeyEvent fun Long.toKeyCode(): Int = when (this) { PlaybackStateCompat.ACTION_PLAY -> KeyEvent.KEYCODE_MEDIA_PLAY @@ -339,6 +397,10 @@ class MusicService : MediaBrowserServiceCompat() { ) = result.sendResult(mutableListOf()) override fun onDestroy() { + if (isReceiverRegistered) { + unregisterReceiver(controlReceiver) + isReceiverRegistered = false + } mediaPlayer?.release() stopForeground(true) isRunning.set(false) diff --git a/local_plugins/music_service/ios/music_service/Sources/music_service/MusicServicePlugin.swift b/local_plugins/music_service/ios/music_service/Sources/music_service/MusicServicePlugin.swift index a81039fa6..5a9a1180e 100644 --- a/local_plugins/music_service/ios/music_service/Sources/music_service/MusicServicePlugin.swift +++ b/local_plugins/music_service/ios/music_service/Sources/music_service/MusicServicePlugin.swift @@ -9,6 +9,7 @@ public class MusicServicePlugin: NSObject, FlutterPlugin { let instance = MusicServicePlugin() registrar.addMethodCallDelegate(instance, channel: channel) self.channel = channel + instance.addNSNotification() } public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { @@ -68,4 +69,35 @@ public class MusicServicePlugin: NSObject, FlutterPlugin { result(FlutterMethodNotImplemented) } } + + private func addNSNotification(){ + NotificationCenter.default.addObserver( + forName: NSNotification.Name("MediaPause"), + object: nil, + queue: .main + ) { _ in + MusicService.shared.pause() + } + NotificationCenter.default.addObserver( + forName: NSNotification.Name("MediaPlay"), + object: nil, + queue: .main + ) { _ in + MusicService.shared.resume() + } + NotificationCenter.default.addObserver( + forName: NSNotification.Name("MediaPrevious"), + object: nil, + queue: .main + ) { _ in + MusicService.shared.previous() + } + NotificationCenter.default.addObserver( + forName: NSNotification.Name("MediaNext"), + object: nil, + queue: .main + ) { _ in + MusicService.shared.next() + } + } }