Browse Source

上传播放控制器接口修复

newdev_shunjiawei
liwei1dao 1 year ago
parent
commit
abd0941701
  1. 24
      local_plugins/chat_api/android/src/main/kotlin/com/yunqiinnovation/chat_api/SystemFunctionHandler.kt
  2. 74
      local_plugins/music_service/android/src/main/kotlin/com/yunqiinnovation/music_service/MusicService.kt
  3. 32
      local_plugins/music_service/ios/music_service/Sources/music_service/MusicServicePlugin.swift

24
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.os.Build
import android.provider.CalendarContract import android.provider.CalendarContract
import android.telephony.SmsManager import android.telephony.SmsManager
import android.util.Log
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.content.ContextCompat.RECEIVER_NOT_EXPORTED
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.* import java.util.*
@ -393,7 +395,10 @@ private class GetCurrentLocationHandler(private val context: Context?) : Functio
private class MediaPlayHandler(private val context: Context?) : FunctionHandler { private class MediaPlayHandler(private val context: Context?) : FunctionHandler {
override suspend fun handle(arguments: Map<String, Any>): String { override suspend fun handle(arguments: Map<String, Any>): 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\": \"已开始播放媒体\"}" return "{\"result\": \"已开始播放媒体\"}"
} }
} }
@ -403,8 +408,12 @@ private class MediaPlayHandler(private val context: Context?) : FunctionHandler
*/ */
private class MediaPauseHandler(private val context: Context?) : FunctionHandler { private class MediaPauseHandler(private val context: Context?) : FunctionHandler {
override suspend fun handle(arguments: Map<String, Any>): String { override suspend fun handle(arguments: Map<String, Any>): 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\": \"已暂停媒体播放\"}" return "{\"result\": \"已暂停媒体播放\"}"
} }
} }
@ -415,7 +424,11 @@ private class MediaPauseHandler(private val context: Context?) : FunctionHandler
private class MediaPreviousHandler(private val context: Context?) : FunctionHandler { private class MediaPreviousHandler(private val context: Context?) : FunctionHandler {
override suspend fun handle(arguments: Map<String, Any>): String { override suspend fun handle(arguments: Map<String, Any>): 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\": \"已切换到上一首\"}" return "{\"result\": \"已切换到上一首\"}"
} }
} }
@ -426,7 +439,10 @@ private class MediaPreviousHandler(private val context: Context?) : FunctionHand
private class MediaNextHandler(private val context: Context?) : FunctionHandler { private class MediaNextHandler(private val context: Context?) : FunctionHandler {
override suspend fun handle(arguments: Map<String, Any>): String { override suspend fun handle(arguments: Map<String, Any>): 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\": \"已切换到下一首\"}" return "{\"result\": \"已切换到下一首\"}"
} }
} }

74
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.NotificationChannel
import android.app.NotificationManager import android.app.NotificationManager
import android.app.PendingIntent import android.app.PendingIntent
import android.content.BroadcastReceiver
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.IntentFilter
import android.graphics.BitmapFactory import android.graphics.BitmapFactory
import android.media.AudioManager import android.media.AudioManager
import android.media.MediaPlayer import android.media.MediaPlayer
@ -41,7 +43,7 @@ class MusicService : MediaBrowserServiceCompat() {
fun isPlaying() = currentStatus fun isPlaying() = currentStatus
fun getCurrentUrl(): String? = currentUrlInternal fun getCurrentUrl(): String? = currentUrlInternal
} }
private var isReceiverRegistered = false
private lateinit var mediaSession: MediaSessionCompat private lateinit var mediaSession: MediaSessionCompat
private lateinit var audioManager: AudioManager private lateinit var audioManager: AudioManager
private var mediaPlayer: MediaPlayer? = null private var mediaPlayer: MediaPlayer? = null
@ -52,6 +54,22 @@ class MusicService : MediaBrowserServiceCompat() {
setupMediaSession() setupMediaSession()
startForeground(NOTIFICATION_ID, createNotification("等待播放","DeepSound","")) startForeground(NOTIFICATION_ID, createNotification("等待播放","DeepSound",""))
audioManager = getSystemService(Context.AUDIO_SERVICE) as AudioManager 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 启动完成") Log.i(TAG, "MediaService 启动完成")
} }
@ -100,6 +118,32 @@ class MusicService : MediaBrowserServiceCompat() {
return START_STICKY 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() { private fun setupMediaSession() {
mediaSession = MediaSessionCompat(this, "MusicMediaSession").apply { mediaSession = MediaSessionCompat(this, "MusicMediaSession").apply {
setFlags( setFlags(
@ -190,19 +234,33 @@ class MusicService : MediaBrowserServiceCompat() {
return builder.build() return builder.build()
} }
fun mediaButtonPendingIntent(action: Long): PendingIntent { fun mediaButtonPendingIntent(action: Long): PendingIntent {
val intent = Intent(this, MusicService::class.java).apply { val keyEvent = KeyEvent(KeyEvent.ACTION_DOWN, action.toKeyCode())
this.action = Intent.ACTION_MEDIA_BUTTON val intent = Intent(Intent.ACTION_MEDIA_BUTTON).apply {
putExtra(Intent.EXTRA_KEY_EVENT, KeyEvent(KeyEvent.ACTION_DOWN, action.toKeyCode())) setPackage(packageName)
putExtra(Intent.EXTRA_KEY_EVENT, keyEvent)
} }
val flags = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { val flags = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
} else { } else {
PendingIntent.FLAG_UPDATE_CURRENT 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 // 转换 PlaybackStateCompat.ACTION 到 KeyEvent
fun Long.toKeyCode(): Int = when (this) { fun Long.toKeyCode(): Int = when (this) {
PlaybackStateCompat.ACTION_PLAY -> KeyEvent.KEYCODE_MEDIA_PLAY PlaybackStateCompat.ACTION_PLAY -> KeyEvent.KEYCODE_MEDIA_PLAY
@ -339,6 +397,10 @@ class MusicService : MediaBrowserServiceCompat() {
) = result.sendResult(mutableListOf()) ) = result.sendResult(mutableListOf())
override fun onDestroy() { override fun onDestroy() {
if (isReceiverRegistered) {
unregisterReceiver(controlReceiver)
isReceiverRegistered = false
}
mediaPlayer?.release() mediaPlayer?.release()
stopForeground(true) stopForeground(true)
isRunning.set(false) isRunning.set(false)

32
local_plugins/music_service/ios/music_service/Sources/music_service/MusicServicePlugin.swift

@ -9,6 +9,7 @@ public class MusicServicePlugin: NSObject, FlutterPlugin {
let instance = MusicServicePlugin() let instance = MusicServicePlugin()
registrar.addMethodCallDelegate(instance, channel: channel) registrar.addMethodCallDelegate(instance, channel: channel)
self.channel = channel self.channel = channel
instance.addNSNotification()
} }
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
@ -68,4 +69,35 @@ public class MusicServicePlugin: NSObject, FlutterPlugin {
result(FlutterMethodNotImplemented) 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()
}
}
} }

Loading…
Cancel
Save