تحدِّد Jetpack Media3 واجهة Player
توضِّح الوظائف الأساسية
لتشغيل ملفات الفيديو والصوت. ExoPlayer
هو التنفيذ التلقائي
لهذه الواجهة في Media3. ننصحك باستخدام ExoPlayer، لأنّه يقدّم مجموعة كاملة من الميزات التي تغطي معظم حالات الاستخدام المتعلّقة بتشغيل المحتوى، ويمكن تعديله للتعامل مع أيّ حالات استخدام إضافية قد تكون لديك. يزيل ExoPlayer أيضًا
التجزئة في الأجهزة ونظام التشغيل لكي يعمل الرمز البرمجي بشكلٍ منتظم
في جميع مكونات Android المتكاملة. يتضمّن ExoPlayer ما يلي:
- إتاحة قوائم التشغيل
- إتاحة مجموعة متنوعة من تنسيقات البث التدريجي والمكيّف
- إتاحة إدراج الإعلانات من جهة العميل والخادم على حدّ سواء
- إتاحة تشغيل المحتوى المحمي بإدارة الحقوق الرقمية
ترشدك هذه الصفحة إلى بعض الخطوات الرئيسية في إنشاء تطبيق تشغيل الوسائط، ويمكنك الانتقال إلى الأدلة الكاملة حول Media3 ExoPlayer للحصول على مزيد من التفاصيل.
الخطوات الأولى
للبدء، أضِف تبعية على وحدات ExoPlayer وواجهة المستخدم والوحدات الشائعة في Jetpack Media3:
implementation "androidx.media3:media3-exoplayer:1.4.1" implementation "androidx.media3:media3-ui:1.4.1" implementation "androidx.media3:media3-common:1.4.1"
استنادًا إلى حالة الاستخدام، قد تحتاج أيضًا إلى وحدات إضافية من Media3،
مثل exoplayer-dash
لتشغيل أحداث البث بتنسيق DASH.
احرص على استبدال 1.4.1
بالإصدار المفضّل من
المكتبة. يمكنك الرجوع إلى ملاحظات الإصدار
للاطّلاع على أحدث إصدار.
إنشاء مشغّل وسائط
باستخدام Media3، يمكنك استخدام عملية التنفيذ المضمّنة Player
لواجهة ExoPlayer
، أو يمكنك إنشاء عملية التنفيذ المخصّصة الخاصة بك.
إنشاء ExoPlayer
في ما يلي أبسط طريقة لإنشاء مثيل ExoPlayer
:
Kotlin
val player = ExoPlayer.Builder(context).build()
Java
ExoPlayer player = new ExoPlayer.Builder(context).build();
يمكنك إنشاء مشغّل الوسائط في طريقة onCreate()
لدورة حياة
Activity
أو Fragment
أو Service
حيث يكون مضمّنًا.
يتضمّن Builder
مجموعة من خيارات التخصيص التي قد تهمّك، مثل:
setAudioAttributes()
لضبط معالجة أولوية الصوتsetHandleAudioBecomingNoisy()
لضبط سلوك التشغيل عند فصل جهاز إخراج الصوتsetTrackSelector()
لضبط اختيار المسار
توفّر Media3 PlayerView
مكوّن واجهة مستخدم يمكنك تضمينه فيملف تنسيق
تطبيقك. يتضمّن هذا المكوّن PlayerControlView
لعناصر التحكّم في
التشغيل وSubtitleView
لعرض الترجمة والشرح وSurface
لعرض
الفيديو.
تحضير المشغّل
أضِف عناصر وسائط إلى قائمة تشغيل لتشغيلها باستخدام طرق مثل
setMediaItem()
وaddMediaItem()
.
بعد ذلك، اتصل بالرقم prepare()
لبدء تحميل الوسائط والحصول على الموارد اللازمة.
يجب عدم تنفيذ هذه الخطوات قبل أن يكون التطبيق في المقدّمة. إذا كان
المشغِّل في وضع Activity
أو Fragment
، يعني ذلك أنّه يتم إعداده في onStart()
method lifecycle (طريقة دورة حياة) على المستوى 24 من واجهة برمجة التطبيقات والإصدارات الأحدث أو onResume()
method lifecycle (طريقة دورة الحياة) على المستوى 23 من واجهة برمجة التطبيقات والإصدارات الأقدم. بالنسبة إلى اللاعب الذي يلعب في Service
،
يمكنك إعداده في onCreate()
.
التحكّم في المشغّل
بعد تجهيز المشغّل، يمكنك التحكّم في التشغيل من خلال استدعاء طُرق في المشغّل، مثل:
play()
وpause()
لبدء التشغيل وإيقافه مؤقتًاseekTo()
للتقديم إلى موضع في ملف الوسائط الحاليseekToNextMediaItem()
وseekToPreviousMediaItem()
للتنقّل في قائمة التشغيل
سيتم تعديل مكونات واجهة المستخدم، مثل PlayerView
أو PlayerControlView
،
وفقًا لذلك عند ربطها بمشغّل.
تحرير اللاعب
يمكن أن يتطلّب التشغيل موارد محدودة، مثل برامج فك ترميز الفيديو، لذا من المهمّ استدعاء release()
في مشغّلك لإخلاء الموارد عندما لا يكون المشغّل مطلوبًا بعد الآن.
إذا كان مشغّل الوسائط في وضع Activity
أو Fragment
، عليك تحريره في onStop()
method lifecycle (طريقة دورة الحياة) على المستوى 24 من واجهة برمجة التطبيقات والإصدارات الأحدث أو onPause()
method (طريقة) على المستوى 23 من واجهة برمجة التطبيقات والإصدارات الأقدم. بالنسبة إلى لاعب في Service
، يمكنك
إصداره في onDestroy()
.
إدارة التشغيل باستخدام جلسة وسائط
على نظام التشغيل Android، توفّر جلسات الوسائط طريقة موحّدة للتفاعل مع مشغّل وسائط في جميع حدود العمليات. يتيح لك ربط جلسة وسائط بجهاز التشغيل الإعلان عن تشغيل الوسائط خارجيًا وتلقّي رسائل التحكّم في التشغيل من مصادر خارجية، على سبيل المثال الدمج مع عناصر التحكّم في وسائط النظام على الأجهزة المزوّدة بشاشة كبيرة وأجهزة الجوّال.
لاستخدام جلسات الوسائط، أضِف عنصرًا تابعًا لمكوّن "جلسة Media3":
implementation "androidx.media3:media3-session:1.4.1"
إنشاء جلسة وسائط
يمكنك إنشاء MediaSession
بعد إعداد مشغّل على النحو التالي:
Kotlin
val player = ExoPlayer.Builder(context).build() val mediaSession = MediaSession.Builder(context, player).build()
Java
ExoPlayer player = new ExoPlayer.Builder(context).build(); MediaSession mediaSession = new MediaSession.Builder(context, player).build();
تُزامن Media3 تلقائيًا حالة Player
مع حالة
MediaSession
. يعمل هذا الإجراء مع أي عملية تنفيذ Player
، بما في ذلك
ExoPlayer
أو CastPlayer
أو
عملية تنفيذ مخصّصة.
منح عناصر التحكّم لعملاء آخرين
يمكن للتطبيقات العميلة تنفيذ عنصر تحكّم في الوسائط
للتحكّم في تشغيل جلسة الوسائط. لتلقّي هذه الطلبات، اضبط عنصر
callback عند
إنشاء MediaSession
.
عندما يكون جهاز التحكّم على وشك الاتصال بجلسة الوسائط، يتمّ استدعاء الأسلوب
onConnect()
. يمكنك استخدام رمز ControllerInfo
المتوفر لتحديد ما إذا كنت تريد قبول
الطلب أو رفضه. يمكنك الاطّلاع على مثال على ذلك في تطبيق Media3 Session التجريبي.
بعد الاتصال، يمكن لوحدة التحكّم إرسال أوامر التشغيل إلى الجلسة. بعد ذلك، تفوِّض الجلسة هذه الأوامر إلى المشغّل. تعالج الجلسة تلقائيًا تعليمات التشغيل وقائمة التشغيل
المحدّدة في واجهة Player
.
تتيح لك طرق الاستدعاء الأخرى التعامل مع طلبات، مثل طلبات
أوامر التشغيل المخصّصة
وتعديل قائمة التشغيل. تتضمّن عمليات الاستدعاء هذه أيضًا عنصر ControllerInfo
حتى تتمكّن من تحديد التحكّم في الوصول على أساس كل طلب على حدة.
تشغيل الوسائط في الخلفية
لمواصلة تشغيل الوسائط عندما لا يكون تطبيقك في المقدّمة، على سبيل المثال،
لتشغيل الموسيقى أو الكتب المسموعة أو ملفات البودكاست حتى عندما لا يكون التطبيق
مفتوحًا لدى المستخدم، يجب تضمين Player
وMediaSession
في
خدمة تعمل في المقدّمة. توفّر Media3 واجهة
MediaSessionService
لهذا الغرض.
تنفيذ MediaSessionService
أنشئ فئة تمثّل MediaSessionService
وأنشئ مثيلًا لمحاولة
MediaSession
في طريقة دورة حياة onCreate()
.
Kotlin
class PlaybackService : MediaSessionService() { private var mediaSession: MediaSession? = null // Create your Player and MediaSession in the onCreate lifecycle event override fun onCreate() { super.onCreate() val player = ExoPlayer.Builder(this).build() mediaSession = MediaSession.Builder(this, player).build() } // Remember to release the player and media session in onDestroy override fun onDestroy() { mediaSession?.run { player.release() release() mediaSession = null } super.onDestroy() } }
Java
public class PlaybackService extends MediaSessionService { private MediaSession mediaSession = null; @Override public void onCreate() { super.onCreate(); ExoPlayer player = new ExoPlayer.Builder(this).build(); mediaSession = new MediaSession.Builder(this, player).build(); } @Override public void onDestroy() { mediaSession.getPlayer().release(); mediaSession.release(); mediaSession = null; super.onDestroy(); } }
في ملف البيان، يجب أن تتضمّن فئة Service
فلتر هدف MediaSessionService
وتطلب الإذن FOREGROUND_SERVICE
لتشغيل
خدمة تعمل في المقدّمة:
<service
android:name=".PlaybackService"
android:foregroundServiceType="mediaPlayback"
android:exported="true">
<intent-filter>
<action android:name="androidx.media3.session.MediaSessionService"/>
</intent-filter>
</service>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
أخيرًا، في الفئة التي أنشأتها، يمكنك إلغاء طريقة onGetSession()
للتحكّم في
وصول العميل إلى جلسة الوسائط. أرسِل MediaSession
لقبول
طلب الربط، أو أرسِل null
لرفض الطلب.
Kotlin
// This example always accepts the connection request override fun onGetSession( controllerInfo: MediaSession.ControllerInfo ): MediaSession? = mediaSession
Java
@Override public MediaSession onGetSession(MediaSession.ControllerInfo controllerInfo) { // This example always accepts the connection request return mediaSession; }
الاتصال بواجهة المستخدم
بما أنّ جلسة الوسائط متوفّرة الآن في Service
منفصل عن Activity
أو
Fragment
حيث يتوفّر واجهة مستخدم المشغّل، يمكنك استخدام MediaController
لربط
الجلستين معًا. في طريقة onStart()
من Activity
أو Fragment
مع
واجهة المستخدم، أنشئ SessionToken
لـ MediaSession
، ثم استخدِم SessionToken
لإنشاء MediaController
. يتم إنشاء MediaController
بشكل غير متزامن.
Kotlin
override fun onStart() { val sessionToken = SessionToken(this, ComponentName(this, PlaybackService::class.java)) val controllerFuture = MediaController.Builder(this, sessionToken).buildAsync() controllerFuture.addListener( { // Call controllerFuture.get() to retrieve the MediaController. // MediaController implements the Player interface, so it can be // attached to the PlayerView UI component. playerView.setPlayer(controllerFuture.get()) }, MoreExecutors.directExecutor() ) }
Java
@Override public void onStart() { SessionToken sessionToken = new SessionToken(this, new ComponentName(this, PlaybackService.class)); ListenableFuture<MediaController> controllerFuture = new MediaController.Builder(this, sessionToken).buildAsync(); controllerFuture.addListener(() -> { // Call controllerFuture.get() to retrieve the MediaController. // MediaController implements the Player interface, so it can be // attached to the PlayerView UI component. playerView.setPlayer(controllerFuture.get()); }, MoreExecutors.directExecutor()) }
تُنفِّذ MediaController
واجهة Player
، لذا يمكنك استخدام METHODS نفسها، مثل play()
وpause()
للتحكّم في التشغيل. على غرار المكونات
الأخرى، تذكَّر تحرير MediaController
عندما لا يعود
مطلوبًا، مثل طريقة onStop()
لدورة حياة Activity
، من خلال استدعاء
MediaController.releaseFuture()
.
نشر إشعار
يجب أن تنشر الخدمات التي تعمل في المقدّمة إشعارًا عندما تكون نشطة. سينشئ
MediaSessionService
تلقائيًا
MediaStyle
إشعارًا
لك على شكل MediaNotification
.
لتقديم إشعار مخصّص، أنشئ
MediaNotification.Provider
باستخدام DefaultMediaNotificationProvider.Builder
أو من خلال إنشاء عملية تنفيذ مخصّصة لواجهة مقدّم الخدمة. أضِف
موفّر الخدمة إلى MediaSession
باستخدام
setMediaNotificationProvider
.
الإعلان عن مكتبة المحتوى
يستند MediaLibraryService
إلى MediaSessionService
من خلال السماح لتطبيقات العميل
بتصفّح محتوى الوسائط الذي يوفّره تطبيقك. تنفِّذ تطبيقات العميل
MediaBrowser
للتفاعل
مع MediaLibraryService
.
يشبه تنفيذ MediaLibraryService
تنفيذ
MediaSessionService
، باستثناء أنّه في onGetSession()
يجب عرض
MediaLibrarySession
بدلاً من MediaSession
. مقارنةً بملف MediaSession.Callback
، يتضمّن ملف MediaLibrarySession.Callback
مزيدًا من الخطوات التي تسمح لأحد عملاء المتصفّح بالتنقّل في المحتوى الذي تقدّمه خدمة مكتبتك.
على غرار MediaSessionService
، يجب تقديم بيان عن MediaLibraryService
في
بيان التطبيق وطلب إذن FOREGROUND_SERVICE
لتشغيل
خدمة تعمل في المقدّمة:
<service
android:name=".PlaybackService"
android:foregroundServiceType="mediaPlayback"
android:exported="true">
<intent-filter>
<action android:name="androidx.media3.session.MediaLibraryService"/>
<action android:name="android.media.browse.MediaBrowserService"/>
</intent-filter>
</service>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
يتضمّن المثال أعلاه فلتر أهداف لكل من MediaLibraryService
وMediaBrowserService
القديم، وذلك للتوافق مع الإصدارات القديمة. يتيح
فلتر الأهداف الإضافي لتطبيقات العملاء التي تستخدم واجهة برمجة التطبيقات MediaBrowserCompat
التعرّف على Service
.
يتيح لك MediaLibrarySession
عرض مكتبة المحتوى في بنية شجرية
، مع MediaItem
جذر واحد. يمكن أن تحتوي كل عقدة MediaItem
في الشجرة على
أي عدد من العقد الفرعية MediaItem
. يمكنك عرض جذر مختلف أو
شجرة مختلفة استنادًا إلى طلب تطبيق العميل. على سبيل المثال، قد تحتوي الشجرة التي تتم إعادتها إلى عميل يبحث عن قائمة بعناصر الوسائط المقترَحة على العنصر الجذر MediaItem
ومستوى واحد من العقد الفرعية MediaItem
فقط،
في حين أنّ الشجرة التي تتم إعادتها إلى تطبيق عميل مختلف قد تمثّل مكتبة محتوى أكثر اكتمالاً.
إنشاء MediaLibrarySession
تُوسّع واجهة برمجة التطبيقات MediaLibrarySession
واجهة برمجة التطبيقات MediaSession
API لإضافة واجهات برمجة تطبيقات لتصفّح المحتوى. مقارنةً بأسلوب
MediaSession
ردّ الاتصال،
يضيف أسلوبMediaLibrarySession
ردّ الاتصال
طُرقًا مثل:
onGetLibraryRoot()
للحالات التي يطلب فيها العميل الجذرMediaItem
لشجرة محتوى-
onGetChildren()
للحالات التي يطلب فيها العميل عناصرMediaItem
في شجرة المحتوى onGetSearchResult()
لحالات طلب العميل لنتائج البحث من شجرة المحتوى لطلب بحث معيّن
ستتضمّن طرق الاستدعاء ذات الصلة عنصر LibraryParams
يتضمّن إشارات إضافية حول نوع شجرة المحتوى التي يهتم بها تطبيق العميل.