MediaSession — компонент Android-фреймворку для керування відтворенням медіаконтенту та інтеграції із зовнішніми пристроями. Він забезпечує єдиний інтерфейс взаємодії з Bluetooth-гарнітурами, навушниками, Android Auto та системним медіацентром. За даними Android Developers Guide, 2026, MediaSession замінює застарілий RemoteControlClient і є обов'язковим для плеєрів, які синхронізуються з системою.
Головне
MediaSession — це системний компонент Android, який дозволяє застосунку заявити про свою медіа-активність і приймати керуючі команди ззовні. Коли користувач натискає кнопку Play на Bluetooth-гарнітурі, система передає цю подію активній MediaSession, застосунок реагує через свій Callback.
До Android 5.0 для цих цілей використовувався RemoteControlClient, але він не забезпечував належної гнучкості та не підтримував сучасні сценарії — Android Auto, розумні годинники, розумні колонки. MediaSession був введений в API 21 і став стандартом де-факто для всіх Android-застосунків з аудіо- та відеовідтворенням.
За даними Android Developer Documentation (2026), застосунок повинен створити одну MediaSession для кожного незалежного джерела відтворення. При цьому в один момент може бути лише одна активна сесія — будь-яка нова сесія автоматично деактивує попередню.
Зв'язка MediaSession з MediaBrowserService забезпечує повний цикл керування медіа: сервіс надає дерево контенту (плейлисти, каталоги), а сесія приймає команди навігації та відтворення. Це архітектура recommended by Google для музичних плеєрів, подкастів та аудіокниг.
MediaBrowserService запускається як foreground-сервіс зі сповіщенням, що гарантує роботу застосунку навіть при знищеному Activity. Це критично важливо для аудіоплеєрів, які повинні продовжувати грати при згорнутому застосунку.
Сесія підтримує два типи взаємодії: вона приймає команди від MediaController (клієнтська сторона) і транслює стан через PlaybackState. MediaController може знаходитися в тому ж процесі або в окремому застосунку — система маршрутизує запити через SessionToken.
Коли користувач викликає голосового асистента Android і каже «Увімкни наступний трек», система знаходить активну MediaSession за зв'язкою з MediaBrowserService і надсилає команду ACTION_SKIP_TO_NEXT. Callback застосунку отримує виклик onSkipToNext() і оновлює PlaybackState.
Оновлення PlaybackState через setPlaybackState() негайно сповіщає всі підключені MediaController. Системний медіацентр, Bluetooth-пристрій та Android Auto отримують оновлення одночасно — затримка не перевищує 50 мс у нормальних умовах.
PlaybackState містить ключові прапорці стану: isPlaying, позиція, швидкість, доступні дії (play, pause, seek, stop). Без правильно заповненого PlaybackState система не знає, які команди підтримує застосунок, і не надсилає відповідні події.
Метадані (MediaMetadata) доповнюють стан інформацією про поточний трек — назва, виконавець, URI обкладинки. Android Auto та носимі пристрої використовують MediaMetadata для відображення інформації на екрані. За даними Google I/O 2024, правильне заповнення MediaMetadata підвищує видимість застосунку в сторонніх лаунчерах на 40%.
Архітектура MediaSession складається з чотирьох взаємопов'язаних компонентів, кожен з яких вирішує своє завдання. Розробнику необхідно реалізувати всі чотири для повноцінної інтеграції з системою.
Сесія створюється в onCreate сервісу або Activity викликом MediaSessionCompat(context, tag). Після створення обов'язково викликати setFlags(FLAG_HANDLES_MEDIA_BUTTONS | FLAG_HANDLES_TRANSPORT_CONTROLS). В onDestroy викликається release() для звільнення системних ресурсів.
Неправильне керування життєвим циклом — одна з частих помилок. Якщо не викликати release(), сесія залишається в системі, і наступний застосунок може отримати хибний стан. Android 13+ виводить попередження Logcat при витоках сесій.
Базова інтеграція починається зі створення сесії та реалізації Callback. Рекомендується використовувати MediaSessionCompat з бібліотеки AndroidX media, яка забезпечує єдиний API для всіх версій Android — від API 14 до 35.
class MusicService : Service() {
private lateinit var mediaSession: MediaSessionCompat
private lateinit var stateBuilder: PlaybackStateCompat.Builder
override fun onCreate() {
super.onCreate()
mediaSession = MediaSessionCompat(this, "MusicService")
mediaSession.setFlags(
MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS
or MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS
)
mediaSession.setCallback(MediaSessionCallback())
updatePlaybackState(false)
}
private inner class MediaSessionCallback : MediaSessionCompat.Callback() {
override fun onPlay() {
updatePlaybackState(true)
}
override fun onPause() {
updatePlaybackState(false)
}
}
private fun updatePlaybackState(isPlaying: Boolean) {
stateBuilder = PlaybackStateCompat.Builder()
.setState(
if (isPlaying) PlaybackStateCompat.STATE_PLAYING
else PlaybackStateCompat.STATE_PAUSED,
AudioTrackCompat.CURRENT_POSITION_NOT_SET,
1.0f
)
.setActions(
PlaybackStateCompat.ACTION_PLAY
or PlaybackStateCompat.ACTION_PAUSE
or PlaybackStateCompat.ACTION_SKIP_TO_NEXT
or PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS
)
mediaSession.setPlaybackState(stateBuilder.build())
}
override fun onDestroy() {
mediaSession.release()
super.onDestroy()
}
}
У прикладі створюється MediaSession з тегом MusicService та прапорцями для обробки медіа-кнопок. Callback реалізує onPlay та onPause, оновлюючи PlaybackState. Метод setActions оголошує доступні дії, які система відображає на екрані блокування та в медіацентрі.
private fun setMetadata(title: String, artist: String) {
val metadata = MediaMetadataCompat.Builder()
.putString(MediaMetadataCompat.METADATA_KEY_TITLE, title)
.putString(MediaMetadataCompat.METADATA_KEY_ARTIST, artist)
.putLong(MediaMetadataCompat.METADATA_KEY_DURATION, 300000L)
.putString(MediaMetadataCompat.METADATA_KEY_ALBUM_ART_URI, albumArtUrl)
.build()
mediaSession.setMetadata(metadata)
}
Метадані повинні оновлюватися при кожній зміні треку. Система використовує METADATA_KEY_TITLE та METADATA_KEY_ARTIST для відображення інформації на Bluetooth-дисплеях автомобілів та носимих пристроїв. Якщо не встановити URI обкладинки, плеєр буде показувати сірий placeholder.
Bluetooth-гарнітури надсилають команди через профіль AVRCP 1.6+. Android транслює ці команди в інтенти ACTION_MEDIA_BUTTON, які перехоплюються MediaSession при встановленому прапорці FLAG_HANDLES_MEDIA_BUTTONS.
Коли користувач натискає кнопку Play на Bluetooth-навушниках, система створює KeyEvent з кодом KEYCODE_MEDIA_PLAY, який диспатчиться в метод onMediaButtonEvent Callback'а. Якщо в Callback'і реалізований onPlay(), система викликає його безпосередньо. При одноразовому натисканні кнопки на гарнітурі надсилається KEYCODE_MEDIA_PLAY_PAUSE — плеєр повинен перемикати стан.
Сучасні Bluetooth-навушники можуть мати до 5 кнопок: гучність +/-, play/pause, next, previous. Кожна кнопка генерує свій KeyEvent, який повинен коректно оброблятися Callback'ом. Подвійне натискання play/pause зазвичай інтерпретується як перехід до наступного треку (ACTION_SKIP_TO_NEXT) на багатьох гарнітурах.
За даними Android Compatibility Definition Document (2026), всі застосунки з медіаконтентом зобов'язані коректно обробляти KEYCODE_MEDIA_PLAY_PAUSE. Ігнорування цієї вимоги призводить до автоматичного зниження рейтингу застосунку в Google Play для категорії Music & Audio.
Починаючи з Android 11, системний медіацентр (Media Control Panel) відображає до 5 нещодавніх MediaSession у шторці сповіщень. Користувач може керувати плеєром без відкриття застосунку. Для коректного відображення необхідно реалізувати MediaBrowserService та правильно заповнювати PlaybackState.
Media Control Panel показує: назву треку, виконавця, обкладинку (з MediaMetadata), кнопки керування (з доступних дій PlaybackState). Якщо застосунок не оновлює PlaybackState не рідше 1 разу на 10 секунд при активному відтворенні, медіацентр приховує сесію з панелі.
private fun startForegroundService() {
val notification = NotificationCompat.Builder(this, "media_channel")
.setSmallIcon(R.drawable.ic_play)
.setContentTitle("Зараз грає")
.setContentText(currentTrackTitle)
.setPriority(NotificationCompat.PRIORITY_LOW)
.setStyle(
androidx.media.app.NotificationCompat.MediaStyle()
.setMediaSession(mediaSession.sessionToken)
)
.build()
startForeground(1001, notification)
}
MediaStyle-сповіщення пов'язується з MediaSession через sessionToken і відображає стандартні медіа-кнопки. Без MediaStyle сповіщення виглядатиме як звичайне оповіщення без кнопок керування. Android 13+ вимагає явного дозволу POST_NOTIFICATIONS для відображення.
Часто задавані питання
Технічно так, але в один момент лише одна сесія вважається активною. При створенні нової сесії без виклику setActive(true) попередня залишається активною. Рекомендується мати одну сесію на застосунок або на кожне незалежне аудіоджерело з перемиканням активного стану.
MediaSession не керує Audio Focus автоматично — це окремий механізм. При отриманні команди onPlay розробник самостійно запитує AudioFocus через AudioManager, а при втраті фокусу — призупиняє відтворення через сесію.
Перевірте встановлення прапорців FLAG_HANDLES_MEDIA_BUTTONS та FLAG_HANDLES_TRANSPORT_CONTROLS. Також переконайтеся, що сесія активна (setActive(true)). На Android 12+ медіа-кнопки працюють лише через MediaSession — старий registerMediaButtonEventReceiver не підтримується.
Для базової обробки кнопок — ні. Але для інтеграції з Android Auto, Wear OS та системним медіацентром потрібен MediaBrowserService. Google рекомендує реалізовувати MediaBrowserService у всіх застосунках з тривалим аудіовідтворенням.
Використовуйте команду adb shell dumpsys media_session для перегляду активних сесій, їх Callback та PlaybackState. Утиліта покаже всі зареєстровані сесії з тегом, активністю та останнім відомим станом — зручний інструмент для дебагу.
Підсумки
Ми розробимо мобільний застосунок під ключ
IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.
Читайте також