MediaSession هو مكون من إطار عمل Android لإدارة تشغيل محتوى الوسائط والتكامل مع الأجهزة الخارجية. يوفر واجهة موحدة للتفاعل مع سماعات Bluetooth وسماعات الرأس وAndroid Auto ومركز الوسائط النظامي. وفقًا لـ Android Developers Guide, 2026، فإن MediaSession يحل محل RemoteControlClient القديم وهو إلزامي للمشغلات التي تتزامن مع النظام.
الخلاصة
MediaSession هو مكون نظام في Android يسمح للتطبيق بالإعلان عن نشاطه الوسائطي واستقبال أوامر التحكم من مصادر خارجية. عندما يضغط المستخدم على زر التشغيل في سماعة Bluetooth، يقوم النظام بتمرير هذا الحدث إلى MediaSession النشطة، ويستجيب التطبيق من خلال Callback الخاص به.
قبل Android 5.0، كان يُستخدم RemoteControlClient لهذا الغرض، لكنه لم يوفر المرونة الكافية ولم يدعم السيناريوهات الحديثة — Android Auto والساعات الذكية ومكبرات الصوت الذكية. تم تقديم MediaSession في API 21 وأصبح المعيار الفعلي لجميع تطبيقات Android التي تحتوي على تشغيل صوتي وفيديو.
وفقًا لوثائق مطوري Android (2026)، يجب على التطبيق إنشاء MediaSession واحدة لكل مصدر تشغيل مستقل. في أي لحظة، يمكن أن تكون جلسة واحدة فقط نشطة — أي جلسة جديدة تقوم تلقائيًا بإلغاء تنشيط الجلسة السابقة.
يوفر الجمع بين MediaSession وMediaBrowserService دورة كاملة لإدارة الوسائط: يقدم الخدمة شجرة محتوى (قوائم تشغيل، كتالوجات)، وتقبل الجلسة أوامر التنقل والتشغيل. هذه هي البنية الموصى بها من Google لمشغلات الموسيقى والبودكاست والكتب الصوتية.
يعمل MediaBrowserService كخدمة أمامية مع إشعار، مما يضمن استمرار عمل التطبيق حتى عند إتلاف النشاط. هذا أمر بالغ الأهمية لمشغلات الصوت التي يجب أن تستمر في التشغيل عند تصغير التطبيق.
تدعم الجلسة نوعين من التفاعل: تستقبل الأوامر من MediaController (الجانب العميل) وتبث الحالة من خلال PlaybackState. يمكن أن يكون MediaController في نفس العملية أو في تطبيق منفصل — يقوم النظام بتوجيه الطلبات عبر SessionToken.
عندما يستدعي المستخدم المساعد الصوتي لـ Android ويقول “شغل المسار التالي”، يجد النظام MediaSession النشطة من خلال اتصالها بـ MediaBrowserService ويرسل الأمر ACTION_SKIP_TO_NEXT. يتلقى Callback التطبيق استدعاء onSkipToNext() ويقوم بتحديث PlaybackState.
يؤدي تحديث PlaybackState عبر setPlaybackState() إلى إعلام جميع مثيلات MediaController المتصلة فورًا. يتلقى مركز الوسائط النظامي وجهاز Bluetooth وAndroid Auto التحديث في وقت واحد — لا يتجاوز التأخير 50 مللي ثانية في الظروف العادية.
يحتوي PlaybackState على علامات الحالة الرئيسية: isPlaying والموضع والسرعة والإجراءات المتاحة (تشغيل، إيقاف مؤقت، بحث، إيقاف). بدون PlaybackState مملوء بشكل صحيح، لا يعرف النظام الأوامر التي يدعمها التطبيق ولا يرسل الأحداث المقابلة.
تكمل البيانات الوصفية (MediaMetadata) الحالة بمعلومات حول المسار الحالي — العنوان والفنان وURI غلاف الألبوم. يستخدم Android Auto والساعات الذكية MediaMetadata لعرض المعلومات على الشاشة. وفقًا لـ Google I/O 2024، فإن الملء الصحيح لـ MediaMetadata يزيد من ظهور التطبيق في مشغلات الطرف الثالث بنسبة 40%.
تتكون بنية MediaSession من أربعة مكونات مترابطة، كل منها يؤدي وظيفته الخاصة. يحتاج المطور إلى تنفيذ الأربعة جميعًا للتكامل الكامل مع النظام.
يتم إنشاء الجلسة في طريقة onCreate لخدمة أو نشاط عن طريق استدعاء 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 الغلاف، سيعرض المشغل عنصرًا نائبًا رماديًا.
ترسل سماعات Bluetooth الأوامر من خلال ملف التعريف AVRCP 1.6+. يقوم Android ببث هذه الأوامر كنوايا ACTION_MEDIA_BUTTON، التي يتم اعتراضها بواسطة MediaSession عند تعيين علم FLAG_HANDLES_MEDIA_BUTTONS.
عندما يضغط المستخدم على زر التشغيل في سماعات Bluetooth، يقوم النظام بإنشاء KeyEvent بالرمز KEYCODE_MEDIA_PLAY، الذي يتم إرساله إلى طريقة onMediaButtonEvent في Callback. إذا تم تنفيذ onPlay() في Callback، يقوم النظام باستدعائه مباشرة. ضغطة واحدة على زر سماعة الرأس ترسل KEYCODE_MEDIA_PLAY_PAUSE — يجب على المشغل تبديل الحالة.
يمكن أن تحتوي سماعات Bluetooth الحديثة على ما يصل إلى 5 أزرار: رفع/خفض الصوت، تشغيل/إيقاف مؤقت، التالي، السابق. يولد كل زر KeyEvent الخاص به، الذي يجب معالجته بشكل صحيح بواسطة Callback. عادةً ما يتم تفسير الضغط المزدوج على زر التشغيل/الإيقاف المؤقت على أنه انتقال إلى المسار التالي (ACTION_SKIP_TO_NEXT) في العديد من سماعات الرأس.
وفقًا لوثيقة تعريف توافق Android (2026)، يجب على جميع التطبيقات التي تحتوي على محتوى وسائط معالجة KEYCODE_MEDIA_PLAY_PAUSE بشكل صحيح. يؤدي تجاهل هذا المطلب إلى انخفاض تلقائي في تصنيف التطبيق في Google Play لفئة الموسيقى والصوت.
بدءًا من Android 11، يعرض مركز الوسائط النظامي (لوحة التحكم في الوسائط) ما يصل إلى 5 جلسات حديثة من MediaSession في لوحة الإشعارات. يمكن للمستخدم التحكم في المشغل دون فتح التطبيق. للعرض الصحيح، يجب تنفيذ MediaBrowserService وملء PlaybackState بشكل صحيح.
تعرض لوحة التحكم في الوسائط: عنوان المسار والفنان والغلاف (من 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 بـ 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 لعرض الجلسات النشطة وCallbacks الخاصة بها وPlaybackState. تعرض هذه الأداة جميع الجلسات المسجلة مع علاماتها وحالة النشاط وآخر حالة معروفة — أداة ملائمة لتصحيح الأخطاء.
الملخص
سنقوم بتطوير تطبيق جوال جاهز
تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.
اقرأ أيضًا