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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 06:12:17