当前位置: 首页 > news >正文

Android 13 接入 MediaSession 详细文档

Android 13 接入 MediaSession 详细文档

一、MediaSession 概述

传统音乐播放应用架构需优先保障音频后台播放,传统方案依赖独立Service异步加载资源并处理播放控制,通过Binder或广播实现界面通信。扩展通知栏控制需额外构建广播接收器,锁屏交互则依赖AIDL等跨进程技术,多终端协同更导致架构复杂化。

MediaSession框架通过C/S架构解耦界面与服务层,核心组件包含MediaSession和MediaController,提供标准化操作接口(播放/暂停等)及自定义扩展能力。Android Support Library v4提供兼容包(类名含Compat后缀),MediaBrowser与MediaBrowserCompat功能一致。该架构简化交互流程、降低多端适配成本并提升开发效率。

二、接入准备

  1. 权限配置

在 AndroidManifest.xml 文件中添加必要的权限声明:

<uses-permission android:name="android.permission.MEDIA_CONTENT_CONTROL" />

注意:MEDIA_CONTENT_CONTROL 权限通常只能授予系统应用或通过特殊方式授权的应用。对于大多数媒体应用来说,仅需要正确实现 MediaSession 即可,无需此权限。

  1. 依赖库

确保你的项目已包含最新的媒体相关依赖:

implementation 'androidx.media:media:1.6.0' // 使用最新稳定版本

三、创建 MediaSession

  1. 基本创建流程

在应用的主 Activity 或 Service 中创建 MediaSession 实例:

// 创建 MediaSessionCompat 实例
MediaSessionCompat mediaSession = new MediaSessionCompat(context, "YourMediaSessionTag");// 设置回调接口
mediaSession.setCallback(new MediaSessionCompat.Callback() {@Overridepublic void onPlay() {super.onPlay();// 处理播放逻辑}@Overridepublic void onPause() {super.onPause();// 处理暂停逻辑}// 实现其他需要的回调方法...
});// 设置会话令牌,供其他组件使用
mediaSession.setSessionToken(sessionToken);// 设置初始播放状态
PlaybackStateCompat state = new PlaybackStateCompat.Builder().setActions(getAvailableActions()).setState(PlaybackStateCompat.STATE_PAUSED, 0, 1.0f).build();
mediaSession.setPlaybackState(state);// 设置元数据
MediaMetadataCompat metadata = new MediaMetadataCompat.Builder().putString(MediaMetadataCompat.METADATA_KEY_TITLE, "Song Title").putString(MediaMetadataCompat.METADATA_KEY_ARTIST, "Artist Name").putBitmap(MediaMetadataCompat.METADATA_KEY_ALBUM_ART, albumArtBitmap).build();
mediaSession.setMetadata(metadata);// 激活会话
mediaSession.setActive(true);
  1. Android 13 特定配置

在 Android 13 中,建议添加以下配置以优化用户体验:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {// 设置媒体会话的锁屏可见性mediaSession.setSessionActivity(PendingIntent.getActivity(context, 0, new Intent(context, MainActivity.class), PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT));// 设置媒体会话的交互模式mediaSession.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS |MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS);
}

四、处理媒体控制

  1. 基本控制方法实现

在 MediaSession.Callback 中实现各种媒体控制逻辑:

@Override
public void onPlay() {// 开始播放媒体if (!isPlaying()) {startPlayback();updatePlaybackState(PlaybackStateCompat.STATE_PLAYING);}
}@Override
public void onPause() {// 暂停媒体播放if (isPlaying()) {pausePlayback();updatePlaybackState(PlaybackStateCompat.STATE_PAUSED);}
}@Override
public void onSkipToNext() {// 跳转到下一首skipToNext();updateMetadata(currentMediaMetadata);
}@Override
public void onSkipToPrevious() {// 跳转到上一首skipToPrevious();updateMetadata(currentMediaMetadata);
}@Override
public void onSeekTo(long pos) {// 跳转到指定位置seekTo(pos);updatePlaybackState(currentState, pos);
}
  1. 自定义操作

Android 13 支持添加自定义操作按钮:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {// 添加自定义操作PlaybackStateCompat.Builder stateBuilder = new PlaybackStateCompat.Builder().setActions(getAvailableActions());// 添加自定义操作,例如"喜欢/收藏"stateBuilder.addCustomAction(new PlaybackStateCompat.CustomAction.Builder("ACTION_LIKE", "Like", R.drawable.ic_like).build());mediaSession.setPlaybackState(stateBuilder.build());
}// 处理自定义操作
@Override
public void onCustomAction(String action, Bundle extras) {if ("ACTION_LIKE".equals(action)) {toggleLikeStatus();}super.onCustomAction(action, extras);
}

五、与系统媒体控制集成

  1. 通知控制

创建与 MediaSession 关联的通知:

// 创建通知渠道(Android 8.0+)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {NotificationChannel channel = new NotificationChannel("media_playback_channel","Media Playback",NotificationManager.IMPORTANCE_LOW);channel.setShowBadge(false);getSystemService(NotificationManager.class).createNotificationChannel(channel);
}// 构建通知
NotificationCompat.Builder builder = new NotificationCompat.Builder(context, "media_playback_channel").setSmallIcon(R.drawable.ic_music_note).setContentTitle("Song Title").setContentText("Artist Name").setLargeIcon(albumArtBitmap).setStyle(new androidx.media.app.NotificationCompat.MediaStyle().setMediaSession(mediaSession.getSessionToken()).setShowActionsInCompactView(0, 1, 2)) // 显示前三个操作按钮.setVisibility(NotificationCompat.VISIBILITY_PUBLIC).setPriority(NotificationCompat.PRIORITY_LOW);// 添加控制按钮
builder.addAction(new NotificationCompat.Action(R.drawable.ic_previous, "Previous", MediaButtonReceiver.buildMediaButtonPendingIntent(context, PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS)));builder.addAction(new NotificationCompat.Action(isPlaying() ? R.drawable.ic_pause : R.drawable.ic_play, isPlaying() ? "Pause" : "Play", MediaButtonReceiver.buildMediaButtonPendingIntent(context, isPlaying() ? PlaybackStateCompat.ACTION_PAUSE : PlaybackStateCompat.ACTION_PLAY)));builder.addAction(new NotificationCompat.Action(R.drawable.ic_next, "Next", MediaButtonReceiver.buildMediaButtonPendingIntent(context, PlaybackStateCompat.ACTION_SKIP_TO_NEXT)));// 显示通知
NotificationManagerCompat.from(context).notify(NOTIFICATION_ID, builder.build());
  1. 锁屏控制

确保锁屏界面正确显示媒体控件:

// 在 MediaSession.Callback 中更新元数据时,系统会自动更新锁屏界面
// 但可以进一步自定义锁屏界面行为
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {// 设置锁屏可见性mediaSession.setSessionActivity(PendingIntent.getActivity(context, 0, new Intent(context, MainActivity.class), PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT));
}

六、处理音频焦点

在 Android 13 中,正确处理音频焦点对于提供良好的用户体验至关重要:

AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);// 请求音频焦点
AudioManager.AudioFocusRequest focusRequest = new AudioManager.AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN).setAudioAttributes(new AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_MEDIA).setContentType(AudioAttributes.CONTENT_TYPE_MUSIC).build()).setAcceptsDelayedFocusGain(true).setWillPauseWhenDucked(true).setOnAudioFocusChangeListener((focusChange) -> {switch (focusChange) {case AudioManager.AUDIOFOCUS_GAIN:// 恢复播放resumePlayback();break;case AudioManager.AUDIOFOCUS_LOSS:// 停止播放并释放资源stopPlayback();break;case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:// 暂停播放pausePlayback();break;case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:// 降低音量setVolume(0.5f);break;}}).build();int result = audioManager.requestAudioFocus(focusRequest);
if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {// 音频焦点请求成功,可以开始播放startPlayback();
}

七、测试与调试

  1. 测试场景

确保覆盖以下测试场景:

  • 设备锁屏状态下控制媒体播放
  • 多任务切换时保持播放状态
  • 连接蓝牙耳机/车载设备时的控制
  • 通知栏控制响应
  • 音频焦点变化处理
  • 自定义操作按钮响应
  1. 调试技巧
  • 使用 Android Studio 的 Logcat 查看 MediaSession 相关日志
  • 通过 adb 命令模拟媒体按键事件:
adb shell input keyevent KEYCODE_MEDIA_PLAY_PAUSE
adb shell input keyevent KEYCODE_MEDIA_NEXT
adb shell input keyevent KEYCODE_MEDIA_PREVIOUS
  • 检查 Notification 是否正确显示媒体信息
  • 验证不同 Android 版本的行为一致性

八、Android 13 新特性适配

  1. 媒体会话增强

Android 13 引入了更精细的媒体会话控制:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {// 设置媒体会话的交互模式mediaSession.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS |MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS |MediaSessionCompat.FLAG_HANDLES_QUEUE_COMMANDS);// 设置媒体会话的扩展信息Bundle extras = new Bundle();extras.putString("com.example.custom_key", "custom_value");mediaSession.setExtras(extras);
}
  1. 隐私权限更新

Android 13 加强了隐私保护,注意处理相关权限:

// 在 AndroidManifest.xml 中声明媒体内容控制权限(如果需要)
<uses-permission android:name="android.permission.MEDIA_CONTENT_CONTROL" tools:ignore="ProtectedPermissions" />

注意:此权限通常只能由系统应用使用
对于第三方应用,应依赖 MediaSession 的标准 API 实现功能

九、性能优化建议

  • 资源管理:在 Activity/Service 销毁时正确释放 MediaSession 资源
  • 电池优化:避免不必要的唤醒和后台播放
  • 内存泄漏:确保 MediaSession 回调中的引用不会导致内存泄漏
  • 响应速度:快速响应媒体控制事件,避免用户操作延迟

十、参考资源

  • https://developer.android.com/reference/androidx/media/session/MediaSessionCompat
  • https://developer.android.com/guide/topics/media-apps/audio-focus
  • https://developer.android.com/training/notify-user/build-notification#media-style

通过遵循本文档中的指导,开发者可以确保其 Android 13 应用中的媒体播放功能与系统深度集成,提供一致且高质量的用户体验。

相关文章:

  • DP之书架
  • CANFD技术在实时运动控制系统中的应用:协议解析、性能测试与未来发展趋势
  • 数据可视化大屏——大数据分析系统
  • 【人工智能】Python中的深度学习模型部署:从训练到生产环境
  • 前端面试宝典---vue实现简化版
  • 用Xshell8配置密钥登陆
  • olama部署deepseek模型
  • 【AI论文】Tina:通过LoRA的微小推理模型
  • 住宅代理IP助力大规模数据采集实战
  • 数组的多种声明方式:类型标注与泛型数组
  • Git分支重命名与推送参数解析
  • 系列位置效应——AI与思维模型【80】
  • 《Keras 3部署全攻略:从新手到实战高手》
  • ShenNiusModularity项目源码学习(22:ShenNius.Admin.Mvc项目分析-7)
  • Axure疑难杂症:全局变量典型应用及思考逻辑(玩转全局变量)
  • 立创EDA
  • 哈希表的模拟实现---C++
  • WSL 中 nvidia-smi: command not found的解决办法
  • 【MCP 应用】CherryStudio 配置和应用 MCP
  • 当高级辅助驾驶遇上“安全驾校”:NVIDIA如何用技术给无人驾驶赋能?
  • 多家媒体及网红走进云南曲靖沾益:感受珠江源头
  • 理想汽车副总裁刘杰:不要被竞争牵着鼻子走,也不迷信护城河
  • 最高法知识产权法庭:6年来新收涉外案件年均增长23.2%
  • 铜钴巨头洛阳钼业一季度净利润同比大增九成,最新宣布超30亿元收购黄金资产
  • 在黄岩朵云书院,邂逅陈丹燕与月季花的故事
  • 远程控制、窃密、挖矿!我国境内捕获“银狐”木马病毒变种