You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android MediaSessionCompat的onMediaButtonEvent失效 无法检测耳机暂停键求助

问题根因

你的代码缺少3个关键配置,导致MediaSession无法被系统优先分发媒体按键事件:

  1. 未在AndroidManifest中注册MediaButtonReceiver及申请对应权限
  2. 未设置PlaybackState,系统默认不会将媒体按键事件分发给无播放状态的MediaSession
  3. 高版本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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.18 15:54:04