Android 11+如何检测Media Controls通知是否存在
原因说明
Android 11 及以上版本中,系统将 Media Controls 媒体控件从普通通知队列中完全剥离,归为系统UI媒体控制区的独立渲染内容,不属于ongoing|conversations|alerting|silent任何一类普通通知类型,因此NotificationListenerService的activeNotifications列表不会返回对应条目,控件的新增、移除、更新也不会触发普通通知的相关回调。
直接调用MediaSessionManager.getActiveSessions()会返回所有应用保活的媒体会话,包含大量后台驻留但未在控制区展示的会话,必须额外增加系统隐藏的展示状态标记过滤,才能得到准确结果。
实现方案
1. 核心判断逻辑
系统会为所有实际展示在下拉通知/快捷设置区Media Controls区域的媒体会话,在其PlaybackState.extras中写入专属状态标记:
- 标记key为
android.media.session.EXTRA_MEDIA_SESSION_STATE - 标记值为
1时,代表该会话对应的媒体控件当前处于可见状态 - 标记值为
0时,代表该会话仅在后台保活,未展示控件
额外补充过滤规则:
- 会话
isActive()返回false时,无论标记值是什么,都不会展示控件 - Android 13及以上版本,若会话的
PlaybackState.state为STATE_STOPPED超过3秒,系统会自动隐藏对应控件,这类会话也需要排除
2. 监听实现
不要依赖NotificationListenerService的通知回调,直接注册MediaSessionManager的活跃会话变化监听,每次回调时按上述规则过滤即可,核心代码如下:
private lateinit var mediaSessionManager: MediaSessionManager private val sessionChangeListener = MediaSessionManager.OnActiveSessionsChangedListener { sessions -> val visibleControlList = sessions.filter { session -> // 过滤失活会话 if (!session.isActive) return@filter false val playbackState = session.playbackState ?: return@filter false // 过滤已停止的会话 if (playbackState.state == PlaybackState.STATE_STOPPED) return@filter false // 读取系统展示状态标记 val controlShowState = playbackState.extras?.getInt( "android.media.session.EXTRA_MEDIA_SESSION_STATE", 0 ) ?: 0 controlShowState == 1 } // visibleControlList 即为当前所有可见的Media Controls对应的会话 val hasVisibleMediaControl = visibleControlList.isNotEmpty() // 后续业务逻辑写在这里 } override fun onListenerConnected() { super.onListenerConnected() mediaSessionManager = getSystemService(Context.MEDIA_SESSION_SERVICE) as MediaSessionManager // 注册监听,第二个参数传入当前NotificationListenerService的组件名 mediaSessionManager.addOnActiveSessionsChangedListener( sessionChangeListener, ComponentName(this, MyNotificationListenerService::class.java) ) } override fun onDestroy() { super.onDestroy() mediaSessionManager.removeOnActiveSessionsChangedListener(sessionChangeListener) }
注意事项
- 调用
addOnActiveSessionsChangedListener和getActiveSessions时,必须传入当前通知监听服务的ComponentName,不能传null,否则无法获取系统隐藏的extra标记,也拿不到完整的活跃会话列表 - 该方案基于AOSP原生逻辑实现,部分深度定制ROM可能修改媒体控件的实现规则,如果遇到判断不准的情况,可以针对对应ROM增加适配逻辑
- 不需要额外申请
MEDIA_CONTENT_CONTROL特权权限,只要用户授予了应用通知访问权限,即可正常读取所有会话信息
内容的提问来源于stack exchange,提问作者markonius
相关产品推荐
相关产品推荐

