غالبًا ما تحتوي تطبيقات الوسائط على مجموعات من ملفات الوسائط المنظَّمة في تسلسل هرمي. على سبيل المثال، الأغاني في ألبوم أو حلقات تلفزيونية في قائمة تشغيل. يُعرف هذا التسلسل الهرمي لملفات الوسائط باسم مكتبة الوسائط.
يوفّر MediaLibraryService واجهة برمجة تطبيقات موحّدة لعرض مكتبة الوسائط والوصول إليها. يمكن أن يكون ذلك مفيدًا، على سبيل المثال، عند إضافة ميزة التوافق مع Android Auto إلى تطبيق الوسائط الذي يوفّر واجهة مستخدم آمنة للسائقين في مكتبة الوسائط.
إنشاء MediaLibraryService
إنّ تنفيذ MediaLibraryService يشبه تنفيذ
MediaSessionService، باستثناء أنّه في طريقة onGetSession()، يجب
عرض MediaLibrarySession بدلاً من MediaSession.
Kotlin
class PlaybackService : MediaLibraryService() { private var mediaLibrarySession: MediaLibrarySession? = null private val callback: MediaLibrarySession.Callback = object : MediaLibrarySession.Callback { /* ... */ } override fun onGetSession(controllerInfo: MediaSession.ControllerInfo): MediaLibrarySession? { // If desired, validate the controller before returning the media library session return mediaLibrarySession } // Create your player and media library session in the onCreate lifecycle event override fun onCreate() { super.onCreate() val player = ExoPlayer.Builder(this).build() mediaLibrarySession = MediaLibrarySession.Builder(this, player, callback).build() } // Remember to release the player and media library session in onDestroy override fun onDestroy() { mediaLibrarySession?.run { player.release() release() mediaLibrarySession = null } super.onDestroy() } }
Java
class PlaybackService extends MediaLibraryService { MediaLibrarySession mediaLibrarySession = null; MediaLibrarySession.Callback callback = new MediaLibrarySession.Callback() { /* ... */ }; @Override public MediaLibrarySession onGetSession(MediaSession.ControllerInfo controllerInfo) { // If desired, validate the controller before returning the media library session return mediaLibrarySession; } // Create your player and media library session in the onCreate lifecycle event @Override public void onCreate() { super.onCreate(); ExoPlayer player = new ExoPlayer.Builder(this).build(); mediaLibrarySession = new MediaLibrarySession.Builder(this, player, callback).build(); } // Remember to release the player and media library session in onDestroy @Override public void onDestroy() { if (mediaLibrarySession != null) { mediaLibrarySession.getPlayer().release(); mediaLibrarySession.release(); mediaLibrarySession = null; } super.onDestroy(); } }
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" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" />
ننصحك بتسجيل خدمتك كواجهة خدمة لكل من المنصة وMedia3:
لضمان التوافق مع العملاء الذين يستخدمون واجهات برمجة التطبيقات لجلسات الوسائط على المنصة، ننصح بتضمين
<action android:name="android.media.browse.MediaBrowserService"/>في عنصرintent-filter. توفّر Media3 تلقائيًا التوافق مع الأنظمة القديمة لواجهة الخدمة هذه.لضمان عمل التطبيقات التي تستخدم Media3 مع خدمتك في المستقبل من خلال واجهة برمجة التطبيقات Media3 API، يجب توفير
<action android:name="androidx.media3.session.MediaLibraryService"/>إلى جانب خيار النظام الأساسي.
يتيح ذلك للتطبيقات العثور على خدمتك من خلال PackageManager والاتصال
بـ MediaBrowser من خلال أي من هاتين الواجهتين.
استخدام MediaLibrarySession
تتوقّع واجهة برمجة التطبيقات MediaLibraryService أن تكون مكتبة الوسائط منظَّمة بتنسيق شجري، مع عقدة جذر واحدة وعقد فرعية يمكن أن تكون قابلة للتشغيل أو قابلة للتصفّح بشكل أكبر.
يوسّع MediaLibrarySession واجهة برمجة التطبيقات MediaSession لإضافة واجهات برمجة تطبيقات لتصفّح المحتوى. مقارنةً بدالة الاستدعاء MediaSession، تضيف دالة الاستدعاء MediaLibrarySession طرقًا مثل:
-
onGetLibraryRoot()عندما يطلب العميل الجذرMediaItemلشجرة المحتوى onGetChildren()عندما يطلب العميل العناصر الفرعية لـMediaItemفي شجرة المحتوىonGetSearchResult()عندما يطلب العميل نتائج البحث من شجرة المحتوى لطلب بحث معيّن
ستتضمّن طرق ردّ الاتصال ذات الصلة عنصر LibraryParams مع إشارات إضافية حول نوع شجرة المحتوى التي يهتم بها تطبيق العميل.
أزرار الأوامر لملفات الوسائط
يمكن لتطبيق الجلسة تحديد أزرار الأوامر التي يتيحها MediaItem في
MediaMetadata. يتيح ذلك تعيين إدخال واحد أو أكثر من إدخالات CommandButton
لملف وسائط يمكن لوحدة التحكّم عرضه واستخدامه لإرسال الأمر المخصّص
للملف إلى الجلسة بطريقة ملائمة.
إعداد أزرار الأوامر في جانب الجلسة
عند إنشاء الجلسة، يعلن تطبيق الجلسة عن مجموعة أزرار الأوامر التي يمكن للجلسة التعامل معها كأوامر مخصّصة:
Kotlin
val allCommandButtons = listOf( CommandButton.Builder(CommandButton.ICON_PLAYLIST_ADD) .setDisplayName(context.getString(R.string.add_to_playlist)) .setSessionCommand(SessionCommand(COMMAND_PLAYLIST_ADD, Bundle.EMPTY)) .setExtras(playlistAddExtras) .build(), CommandButton.Builder(CommandButton.ICON_RADIO) .setDisplayName(context.getString(R.string.radio_station)) .setSessionCommand(SessionCommand(COMMAND_RADIO, Bundle.EMPTY)) .setExtras(radioExtras) .build(), ) // Add all command buttons for media items supported by the session. val session = MediaSession.Builder(context, player) .setCommandButtonsForMediaItems(allCommandButtons) .build()
Java
ImmutableList<CommandButton> allCommandButtons = ImmutableList.of( new CommandButton.Builder(CommandButton.ICON_PLAYLIST_ADD) .setDisplayName(context.getString(R.string.add_to_playlist)) .setSessionCommand(new SessionCommand(COMMAND_PLAYLIST_ADD, Bundle.EMPTY)) .setExtras(playlistAddExtras) .build(), new CommandButton.Builder(CommandButton.ICON_RADIO) .setDisplayName(context.getString(R.string.radio_station)) .setSessionCommand(new SessionCommand(COMMAND_RADIO, Bundle.EMPTY)) .setExtras(radioExtras) .build()); // Add all command buttons for media items supported by the session. MediaSession session = new MediaSession.Builder(context, player) .setCommandButtonsForMediaItems(allCommandButtons) .build();
عند إنشاء ملف وسائط، يمكن لتطبيق الجلسة إضافة مجموعة من أرقام تعريف الأوامر المتوافقة التي تشير إلى أوامر الجلسة لأزرار الأوامر التي تم إعدادها عند إنشاء الجلسة:
Kotlin
val mediaItem = MediaItem.Builder() .setMediaMetadata( MediaMetadata.Builder() .setSupportedCommands(listOf(COMMAND_PLAYLIST_ADD, COMMAND_RADIO)) .build() ) .build()
Java
MediaItem mediaItem = new MediaItem.Builder() .setMediaMetadata( new MediaMetadata.Builder() .setSupportedCommands(ImmutableList.of(COMMAND_PLAYLIST_ADD, COMMAND_RADIO)) .build()) .build();
عندما يتصل جهاز تحكّم أو متصفّح أو يستدعي طريقة أخرى للجلسة
Callback، يمكن لتطبيق الجلسة فحص ControllerInfo الذي تم تمريره إلى
عملية الاستدعاء للحصول على الحد الأقصى لعدد أزرار الأوامر التي يمكن لجهاز التحكّم أو المتصفّح
عرضها. يوفّر ControllerInfo الذي تم تمريره إلى طريقة رد الاتصال
دالة getter للوصول إلى هذه القيمة بسهولة. يتم ضبط القيمة تلقائيًا على 0، ما يشير إلى أنّ المتصفّح أو وحدة التحكّم لا يتيحان هذه الميزة:
Kotlin
override fun onGetItem( session: MediaLibrarySession, browser: MediaSession.ControllerInfo, mediaId: String, ): ListenableFuture<LibraryResult<MediaItem>> { val settableFuture = SettableFuture.create<LibraryResult<MediaItem>>() val maxCommandsForMediaItems = browser.maxCommandsForMediaItems loadMediaItemAsync(settableFuture, mediaId, maxCommandsForMediaItems) return settableFuture }
Java
@Override public ListenableFuture<LibraryResult<MediaItem>> onGetItem( MediaLibraryService.MediaLibrarySession session, ControllerInfo browser, String mediaId) { SettableFuture<LibraryResult<MediaItem>> settableFuture = SettableFuture.create(); int maxCommandsForMediaItems = browser.getMaxCommandsForMediaItems(); loadMediaItemAsync(settableFuture, mediaId, maxCommandsForMediaItems); return settableFuture; }
عند معالجة إجراء مخصّص تم إرساله لملف وسائط، يمكن لتطبيق الجلسة الحصول على رقم تعريف ملف الوسائط من الوسيطات Bundle التي تم تمريرها إلى onCustomCommand:
Kotlin
override fun onCustomCommand( session: MediaSession, controller: MediaSession.ControllerInfo, customCommand: SessionCommand, args: Bundle, ): ListenableFuture<SessionResult> { val mediaItemId = args.getString(MediaConstants.EXTRA_KEY_MEDIA_ID) return if (mediaItemId != null) handleCustomCommandForMediaItem(controller, customCommand, mediaItemId, args) else handleCustomCommand(controller, customCommand, args) }
Java
@Override public ListenableFuture<SessionResult> onCustomCommand( MediaSession session, ControllerInfo controller, SessionCommand customCommand, Bundle args) { String mediaItemId = args.getString(MediaConstants.EXTRA_KEY_MEDIA_ID); return mediaItemId != null ? handleCustomCommandForMediaItem(controller, customCommand, mediaItemId, args) : handleCustomCommand(controller, customCommand, args); }
استخدام أزرار الأوامر كمتصفّح أو وحدة تحكّم
من جانب MediaController، يمكن للتطبيق تحديد الحد الأقصى لعدد أزرار الأوامر التي يتيحها لملف وسائط عند إنشاء MediaController أو MediaBrowser:
Kotlin
val browserFuture = MediaBrowser.Builder(context, sessionToken).setMaxCommandsForMediaItems(3).buildAsync()
Java
ListenableFuture<MediaBrowser> browserFuture = new MediaBrowser.Builder(context, sessionToken).setMaxCommandsForMediaItems(3).buildAsync();
عند الاتصال بالجلسة، يمكن لتطبيق وحدة التحكّم تلقّي أزرار الأوامر المتوافقة مع ملف الوسائط والتي يملك وحدة التحكّم الأمر المتاح الذي يمنحه تطبيق الجلسة:
Kotlin
val commandButtonsForMediaItem = controller.getCommandButtonsForMediaItem(mediaItem)
Java
ImmutableList<CommandButton> commandButtonsForMediaItem = controller.getCommandButtonsForMediaItem(mediaItem);
Kotlin
val future = controller.sendCustomCommand( requireNotNull(addToPlaylistButton.sessionCommand), mediaItem, Bundle.EMPTY, )
Java
ListenableFuture<SessionResult> future = controller.sendCustomCommand( checkNotNull(addToPlaylistButton.sessionCommand), mediaItem, Bundle.EMPTY);