MediaSession — مؤلفه چارچوب اندروید برای مدیریت پخش محتوای رسانهای و یکپارچهسازی با دستگاههای خارجی است. این یک رابط واحد برای تعامل با هدستهای بلوتوث، هدفونها، Android Auto و مرکز رسانه سیستمی فراهم میکند. بر اساس Android Developers Guide, 2026، MediaSession جایگزین RemoteControlClient قدیمی شده و برای پخشکنندههایی که با سیستم همگامسازی میشوند الزامی است.
نکات اصلی
MediaSession — یک مؤلفه سیستمی اندروید است که به برنامه اجازه میدهد فعالیت رسانهای خود را اعلام کرده و دستورات کنترلی از خارج دریافت کند. هنگامی که کاربر دکمه Play را روی هدست بلوتوث فشار میدهد، سیستم این رویداد را به MediaSession فعال منتقل میکند و برنامه از طریق Callback خود واکنش نشان میدهد.
قبل از اندروید 5.0 برای این اهداف از RemoteControlClient استفاده میشد، اما انعطافپذیری لازم را نداشت و سناریوهای مدرن — Android Auto، ساعتهای هوشمند، بلندگوهای هوشمند را پشتیبانی نمیکرد. MediaSession در API 21 معرفی شد و به استاندارد دوفاکتو برای همه برنامههای اندروید با پخش صوتی و تصویری تبدیل شد.
بر اساس Android Developer Documentation (2026)، برنامه باید برای هر منبع پخش مستقل یک MediaSession ایجاد کند. در هر لحظه فقط یک جلسه فعال میتواند وجود داشته باشد — هر جلسه جدید به طور خودکار جلسه قبلی را غیرفعال میکند.
ترکیب MediaSession با MediaBrowserService چرخه کامل مدیریت رسانه را فراهم میکند: سرویس درخت محتوا (لیستهای پخش، کاتالوگها) را ارائه میدهد و جلسه دستورات ناوبری و پخش را دریافت میکند. این معماری توصیهشده توسط Google برای پخشکنندههای موسیقی، پادکستها و کتابهای صوتی است.
MediaBrowserService به عنوان یک foreground-service با اعلان راهاندازی میشود که عملکرد برنامه را حتی پس از کشته شدن Activity تضمین میکند. این برای پخشکنندههای صوتی که باید در هنگام کوچکسازی برنامه به پخش ادامه دهند حیاتی است.
جلسه دو نوع تعامل را پشتیبانی میکند: دستورات را از MediaController (سمت مشتری) دریافت میکند و وضعیت را از طریق PlaybackState پخش میکند. MediaController میتواند در همان فرآیند یا در یک برنامه جداگانه باشد — سیستم درخواستها را از طریق SessionToken مسیریابی میکند.
هنگامی که کاربر دستیار صوتی اندروید را فراخوانی کرده و میگوید «آهنگ بعدی را پخش کن»، سیستم MediaSession فعال را از طریق ارتباط با MediaBrowserService پیدا کرده و دستور ACTION_SKIP_TO_NEXT را ارسال میکند. Callback برنامه فراخوانی onSkipToNext() را دریافت کرده و PlaybackState را بهروزرسانی میکند.
بهروزرسانی PlaybackState از طریق setPlaybackState() بلافاصله همه MediaControllerهای متصل را مطلع میکند. مرکز رسانه سیستمی، دستگاه بلوتوث و Android Auto همزمان بهروزرسانی را دریافت میکنند — تأخیر در شرایط عادی از 50 میلیثانیه تجاوز نمیکند.
PlaybackState شامل پرچمهای وضعیت کلیدی است: isPlaying، موقعیت، سرعت، اقدامات موجود (play، pause، seek، stop). بدون PlaybackState پر شده صحیح، سیستم نمیداند برنامه چه دستوراتی را پشتیبانی میکند و رویدادهای مربوطه را ارسال نمیکند.
فرادادهها (MediaMetadata) وضعیت را با اطلاعات مربوط به آهنگ فعلی تکمیل میکنند — title, artist, album art 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() فراخوانی نشود، جلسه در سیستم باقی میماند و برنامه بعدی ممکن است وضعیت نادرستی دریافت کند. اندروید 13+ در هنگام نشت جلسه در Logcat اخطار نشان میدهد.
یکپارچهسازی پایه با ایجاد جلسه و پیادهسازی Callback آغاز میشود. توصیه میشود از MediaSessionCompat از کتابخانه AndroidX media استفاده کنید که API یکپارچهای برای تمام نسخههای اندروید — از 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 برای نمایش اطلاعات روی نمایشگرهای بلوتوث خودروها و دستگاههای پوشیدنی استفاده میکند. اگر URI جلد تنظیم نشود، پخشکننده یک placeholder خاکستری نشان میدهد.
هدستهای بلوتوث دستورات را از طریق پروفایل AVRCP 1.6+ ارسال میکنند. اندروید این دستورات را به intentهای ACTION_MEDIA_BUTTON منتقل میکند که توسط MediaSession با پرچم FLAG_HANDLES_MEDIA_BUTTONS گرفته میشوند.
هنگامی که کاربر دکمه Play را روی هدفون بلوتوث فشار میدهد، سیستم یک KeyEvent با کد KEYCODE_MEDIA_PLAY ایجاد میکند که به متد onMediaButtonEvent Callback ارسال میشود. اگر در Callback متد onPlay() پیادهسازی شده باشد، سیستم مستقیماً آن را فراخوانی میکند. با فشار تکی دکمه روی هدست، KEYCODE_MEDIA_PLAY_PAUSE ارسال میشود — پخشکننده باید وضعیت را تغییر دهد.
هدفونهای بلوتوث مدرن میتوانند تا 5 دکمه داشته باشند: صدا +/-، play/pause، next، previous. هر دکمه KeyEvent مخصوص خود را تولید میکند که باید به درستی توسط Callback پردازش شود. فشار دوبل play/pause معمولاً در بسیاری از هدفونها به عنوان رفتن به آهنگ بعدی (ACTION_SKIP_TO_NEXT) تفسیر میشود.
بر اساس Android Compatibility Definition Document (2026)، تمام برنامههای دارای محتوای رسانهای موظف به پردازش صحیح KEYCODE_MEDIA_PLAY_PAUSE هستند. نادیده گرفتن این الزام منجر به کاهش خودکار رتبه برنامه در Google Play برای دسته Musiqi & Audio میشود.
از اندروید 11 به بعد، مرکز رسانه سیستمی (Media Control Panel) تا 5 جلسه MediaSession اخیر را در پنل اعلانها نمایش میدهد. کاربر میتواند بدون باز کردن برنامه، پخشکننده را کنترل کند. برای نمایش صحیح باید MediaBrowserService پیادهسازی شده و PlaybackState به درستی پر شود.
Media Control Panel نمایش میدهد: نام آهنگ، اجراکننده، جلد (از MediaMetadata)، دکمههای کنترل (از اقدامات مجاز PlaybackState). اگر برنامه PlaybackState را حداقل هر 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 از طریق sessionToken با MediaSession مرتبط میشود و دکمههای استاندارد رسانه را نمایش میدهد. بدون MediaStyle، اعلان مانند یک اخطار معمولی بدون دکمههای کنترل به نظر میرسد. اندروید 13+ برای نمایش نیاز به مجوز صریح POST_NOTIFICATIONS دارد.
سوالات متداول
از نظر فنی بله، اما در یک لحظه فقط یک جلسه فعال محسوب میشود. هنگام ایجاد جلسه جدید بدون فراخوانی setActive(true)، جلسه قبلی فعال باقی میماند. توصیه میشود به ازای هر برنامه یا هر منبع صوتی مستقل یک جلسه با تغییر وضعیت فعال داشته باشید.
MediaSession به طور خودکار Audio Focus را مدیریت نمیکند — این یک مکانیزم جداگانه است. هنگام دریافت دستور onPlay، توسعهدهنده شخصاً از طریق AudioManager درخواست AudioFocus میکند و هنگام از دست دادن فوکوس، پخش را از طریق جلسه متوقف میکند.
تنظیم پرچمهای FLAG_HANDLES_MEDIA_BUTTONS و FLAG_HANDLES_TRANSPORT_CONTROLS را بررسی کنید. همچنین مطمئن شوید جلسه فعال است (setActive(true)). در اندروید 12+ دکمههای رسانه فقط از طریق MediaSession کار میکنند — registerMediaButtonEventReceiver قدیمی پشتیبانی نمیشود.
برای پردازش پایه دکمهها — خیر. اما برای یکپارچهسازی با Android Auto، Wear OS و مرکز رسانه سیستمی، MediaBrowserService مورد نیاز است. Google پیادهسازی MediaBrowserService را در همه برنامههای با پخش طولانی مدت صوتی توصیه میکند.
از دستور adb shell dumpsys media_session برای مشاهده جلسات فعال، Callback و PlaybackState آنها استفاده کنید. این ابزار همه جلسات ثبتشده را با تگ، فعالیت و آخرین وضعیت شناخته شده نشان میدهد — ابزاری مناسب برای اشکالزدایی.
خلاصه
ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد
IT Sectr از سال 2017 برنامههای iOS و Android را برای استارتاپها و کسبوکارها ایجاد میکند. ما به شما مشاوره میدهیم و بهترین راهحل را پیشنهاد خواهیم کرد.
همچنین بخوانید