Android MediaSessionCompat的onMediaButtonEvent失效 无法检测耳机暂停键求助
问题根因
你的代码缺少3个关键配置,导致MediaSession无法被系统优先分发媒体按键事件:
- 未在AndroidManifest中注册MediaButtonReceiver及申请对应权限
- 未设置PlaybackState,系统默认不会将媒体按键事件分发给无播放状态的MediaSession
- 高版本Android未动态申请蓝牙相关权限
缺失配置补充
AndroidManifest.xml 配置
<!-- 基础媒体控制权限 --> <uses-permission android:name="android.permission.MEDIA_CONTENT_CONTROL" /> <!-- Android 12+ 蓝牙耳机按键所需权限 --> <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" /> <!-- 适配低版本蓝牙权限 --> <uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30" /> <!-- 前台服务权限(如果使用后台Service持有MediaSession) --> <uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" /> <application ...> <!-- 注册MediaButton接收器 --> <receiver android:name="androidx.media.session.MediaButtonReceiver" android:exported="true"> <intent-filter> <action android:name="android.intent.action.MEDIA_BUTTON" /> </intent-filter> </receiver> </application>
动态权限申请(Android 12+ 必须)
在Activity onCreate中加入权限申请逻辑,否则无法接收蓝牙耳机的按键事件。
修正后的完整可运行代码
import android.Manifest import android.content.ComponentName import android.content.Intent import android.content.pm.PackageManager import android.os.Build import android.os.Bundle import android.support.v4.media.session.MediaSessionCompat import android.support.v4.media.session.PlaybackStateCompat import androidx.appcompat.app.AppCompatActivity import androidx.core.app.ActivityCompat import androidx.core.content.ContextCompat import androidx.media.session.MediaButtonReceiver class MainActivity : AppCompatActivity() { private lateinit var mMediaSessionCompat: MediaSessionCompat private val mMediaSessionCallback: MediaSessionCompat.Callback = object : MediaSessionCompat.Callback() { override fun onMediaButtonEvent(mediaButtonEvent: Intent): Boolean { println("WORKS!!!") // 此处可自行解析KeyEvent处理暂停/播放按键逻辑 return true // 消费事件,不再往下分发 } } private fun initMediaSession() { val mediaButtonReceiver = ComponentName(applicationContext, MediaButtonReceiver::class.java) mMediaSessionCompat = MediaSessionCompat(applicationContext, "HeadsetButtonTag", mediaButtonReceiver, null) mMediaSessionCompat.setCallback(mMediaSessionCallback) mMediaSessionCompat.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS or MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS) // 关键:设置模拟播放状态,让系统判定你的应用需要接收媒体按键 val playbackState = PlaybackStateCompat.Builder() .setState(PlaybackStateCompat.STATE_PLAYING, 0, 1f) .setActions( PlaybackStateCompat.ACTION_MEDIA_BUTTON or PlaybackStateCompat.ACTION_PLAY_PAUSE or PlaybackStateCompat.ACTION_PAUSE or PlaybackStateCompat.ACTION_PLAY ) .build() mMediaSessionCompat.setPlaybackState(playbackState) mMediaSessionCompat.isActive = true } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // 先申请权限再初始化MediaSession checkPermissionAndInit() } private fun checkPermissionAndInit() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { if (ContextCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_CONNECT) == PackageManager.PERMISSION_GRANTED) { initMediaSession() } else { ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.BLUETOOTH_CONNECT), 1001) } } else { initMediaSession() } } override fun onRequestPermissionsResult( requestCode: Int, permissions: Array<out String>, grantResults: IntArray ) { super.onRequestPermissionsResult(requestCode, permissions, grantResults) if (requestCode == 1001 && grantResults.firstOrNull() == PackageManager.PERMISSION_GRANTED) { initMediaSession() } } override fun onDestroy() { super.onDestroy() mMediaSessionCompat.release() } }
后台长期生效补充说明
如果需要应用切后台、设备重启后仍然能接收按键,需要将MediaSession的持有逻辑放到前台Service中,并在Service中显示常驻前台通知,避免被系统回收。测试时请先关闭其他后台运行的音乐、视频类应用,避免它们抢占媒体按键事件优先级,部分国产ROM还需要手动给应用开启「媒体控制」权限。
内容的提问来源于stack exchange,提问作者Blue
相关产品推荐
相关产品推荐

