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

如何在Wear OS的Jetpack Compose中获取当前播放歌曲及解决权限异常?

在Wear OS Jetpack Compose中获取当前播放歌曲的方案

首先纠正一个误区:你用MediaSessionService是用来实现自己的媒体播放服务(比如你的APP作为音乐播放器),而非获取其他应用的播放状态。要获取系统中当前活跃的媒体会话信息,正确的方式是使用MediaControllerCompat结合系统媒体会话管理。

一、解决你遇到的权限异常(若确需使用MediaSessionService)

如果你的场景是开发自己的媒体播放器,出现java.lang.SecurityException: Missing permission to control media的原因是缺少必要权限,按以下步骤修复:

  1. 在AndroidManifest.xml中添加权限与服务声明:
    <!-- 媒体控制核心权限 -->
    <uses-permission android:name="android.permission.MEDIA_CONTENT_CONTROL" />
    <!-- Android 13+ 读取本地音频文件权限(若需访问本地媒体) -->
    <uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
    
    <!-- 声明MediaSessionService -->
    <service
        android:name=".YourMediaSessionService"
        android:exported="true">
        <intent-filter>
            <action android:name="android.media.session.MediaSessionService" />
        </intent-filter>
    </service>
    
  2. 动态申请权限:Android 6.0+ 需动态申请READ_MEDIA_AUDIO(13+)或READ_EXTERNAL_STORAGE(低版本),MEDIA_CONTENT_CONTROL通常会被系统自动授予给媒体类应用,无需额外动态申请。

二、获取当前播放歌曲的最优实现(Wear OS Jetpack Compose)

使用MediaControllerCompat监听系统活跃媒体会话,是获取当前播放信息的标准方案,步骤如下:

1. 添加依赖

在Module级build.gradle中引入媒体组件依赖:

implementation "androidx.media:media:1.6.0"
implementation "androidx.wear:wear-media:1.0.0"

2. Compose中实现监听逻辑

通过MediaSessionManagerCompat监听活跃会话变化,获取媒体元数据与播放状态:

@Composable
fun NowPlayingStatus() {
    val context = LocalContext.current
    val mediaSessionManager = remember { MediaSessionManagerCompat.getSessionManager(context) }
    var currentMediaMeta by remember { mutableStateOf<MediaMetadataCompat?>(null) }
    var playbackState by remember { mutableStateOf<PlaybackStateCompat?>(null) }

    // 监听活跃媒体会话变更
    DisposableEffect(mediaSessionManager) {
        val sessionCallback = object : MediaSessionManagerCompat.OnActiveSessionsChangedListener {
            override fun onActiveSessionsChanged(controllers: MutableList<MediaControllerCompat>?) {
                controllers?.firstOrNull()?.run {
                    currentMediaMeta = metadata
                    playbackState = playbackState
                    // 监听实时播放状态与元数据变化
                    registerCallback(object : MediaControllerCompat.Callback() {
                        override fun onMetadataChanged(metadata: MediaMetadataCompat?) {
                            currentMediaMeta = metadata
                        }

                        override fun onPlaybackStateChanged(state: PlaybackStateCompat?) {
                            playbackState = state
                        }
                    })
                }
            }
        }

        mediaSessionManager.addOnActiveSessionsChangedListener(
            sessionCallback,
            ComponentName(context, MediaBrowserServiceCompat::class.java)
        )

        onDispose {
            mediaSessionManager.removeOnActiveSessionsChangedListener(sessionCallback)
        }
    }

    // 渲染当前播放信息
    Column(
        modifier = Modifier.fillMaxSize(),
        horizontalAlignment = Alignment.CenterHorizontally,
        verticalArrangement = Arrangement.Center
    ) {
        currentMediaMeta?.let { meta ->
            Text(text = "当前播放: ${meta.description.title ?: "未知歌曲"}", fontWeight = FontWeight.Bold)
            Text(text = "歌手: ${meta.description.subtitle ?: "未知歌手"}")
            playbackState?.let { state ->
                Text(text = "状态: ${if (state.state == PlaybackStateCompat.STATE_PLAYING) "播放中" else "已暂停"}")
            }
        } ?: run {
            Text(text = "暂无媒体播放")
        }
    }
}

3. 权限处理

在Compose中动态申请必要权限,确保能读取媒体元数据:

val permissionLauncher = rememberLauncherForActivityResult(
    contract = ActivityResultContracts.RequestPermission(),
    onResult = { isGranted ->
        if (isGranted) {
            // 权限授予后可触发会话刷新逻辑
        }
    }
)

LaunchedEffect(Unit) {
    val requiredPermission = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
        Manifest.permission.READ_MEDIA_AUDIO
    } else {
        Manifest.permission.READ_EXTERNAL_STORAGE
    }

    if (ContextCompat.checkSelfPermission(context, requiredPermission) != PackageManager.PERMISSION_GRANTED) {
        permissionLauncher.launch(requiredPermission)
    }
}

三、关键注意事项

  • 部分第三方音乐APP可能未暴露媒体会话,导致无法获取其播放状态,这是应用自身的限制,无法通过代码解决;
  • 测试时需确保有媒体APP处于活跃播放状态,否则currentMediaMeta会为null;
  • 若开发自己的播放器,MediaSessionService需正确初始化MediaSessionCompat并设置回调,确保会话被系统识别。

内容的提问来源于stack exchange,提问作者Matanya Asis

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 11:27:48