غالبًا ما تحتوي تطبيقات الوسائط على مجموعات من عناصر الوسائط، ويتم تنظيمها في تسلسل هرمي. على سبيل المثال، الأغاني في ألبوم أو حلقات تلفزيونية في قائمة تشغيل يُعرف هذا التسلسل الهرمي لمواد الوسائط باسم مكتبة الوسائط.
توفّر MediaLibraryService
واجهة برمجة تطبيقات موحّدة لعرض مكتبة الوسائط والوصول إليها. يمكن أن يكون ذلك مفيدًا، على سبيل المثال، عند إضافة ميزة استخدام
Android Auto إلى تطبيق الوسائط الذي يقدّم واجهة مستخدم
آمنة للسائقين لمكتبة الوسائط.
إنشاء MediaLibraryService
يشبه تنفيذ MediaLibraryService
تنفيذ MediaSessionService
،
باستثناء أنّه في طريقة onGetSession()
، يجب
عرض MediaLibrarySession
بدلاً من MediaSession
.
Kotlin
class PlaybackService : MediaLibraryService() { var mediaLibrarySession: MediaLibrarySession? = null var callback: MediaLibrarySession.Callback = object : MediaLibrarySession.Callback {...} // If desired, validate the controller before returning the media library session override fun onGetSession(controllerInfo: MediaSession.ControllerInfo): MediaLibrarySession? = 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.MediaSessionService"/>
</intent-filter>
</service>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<!-- For targetSdk 34+ -->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" />
استخدام MediaLibrarySession
تتوقع واجهة برمجة التطبيقات MediaLibraryService
أن تكون مكتبة الوسائط منضمّنة في ملف بتنسيق
شجرة، مع عقدة جذر واحدة وعقد فرعية قد تكون
قابلة للتشغيل
أو قابلة للتصفّح بشكل أكبر.
تُوسّع واجهة برمجة التطبيقات MediaLibrarySession
واجهة برمجة التطبيقات MediaSession
API لإضافة واجهات برمجة تطبيقات لتصفّح المحتوى. مقارنةً بأسلوب
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)) .setDisplayName("Add to playlist") .setIconResId(R.drawable.playlist_add) .setSessionCommand(SessionCommand(COMMAND_PLAYLIST_ADD, Bundle.EMPTY)) .setExtras(playlistAddExtras) .build(), CommandButton.Builder(CommandButton.ICON_RADIO) .setDisplayName(context.getString(R.string.radio_station)) .setIconResId(R.drawable.radio) .setSessionCommand(SessionCommand(COMMAND_RADIO, Bundle.EMPTY)) .setExtras(radioExtras) .build(), // possibly more here ) // 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("Add to playlist") .setIconUri(Uri.parse("http://www.example.com/icon/playlist_add")) .setSessionCommand(new SessionCommand(COMMAND_PLAYLIST_ADD, Bundle.EMPTY)) .setExtras(playlistAddExtras) .build(), new CommandButton.Builder(CommandButton.ICON_RADIO) .setDisplayName("Radio station") .setIconUri(Uri.parse("http://www.example.com/icon/radio")) .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
للحصول على الحد الأقصى لعدد أزرار الأوامر التي يمكن لجهاز التحكّم أو المتصفّح عرضها. يقدّم العنصر ControllerInfo
الذي تم تمريره إلى طريقة ردّ اتصال أسلوبًا
للحصول على هذه القيمة بسهولة. يتم ضبط القيمة تلقائيًا على 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 scope.launch { loadMediaItem(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
، يمكن للتطبيق تحديد الحد الأقصى لعدد buttons
الأمر التي يتيحها لعنصر وسائط عند إنشاء MediaController
أو
MediaBrowser
:
Kotlin
val browserFuture = MediaBrowser.Builder(context, sessionToken) .setMaxCommandsForMediaItems(3) .buildAsync()
Java
ListenableFuture<MediaBrowser> browserFuture = new MediaBrowser.Builder(context, sessionToken) .setMaxCommandsForMediaItems(3) .buildAsync();
عند الاتصال بالجلسة، يمكن لتطبيق التحكّم تلقّي buttons buttons الأمر المتاح الذي منحه تطبيق الجلسة لسماح وحدة التحكّم بتنفيذه:
Kotlin
val commandButtonsForMediaItem: List<CommandButton> = controller.getCommandButtonsForMediaItem(mediaItem)
Java
ImmutableList<CommandButton> commandButtonsForMediaItem = controller.getCommandButtonsForMediaItem(mediaItem);
لتسهيل الأمر، يمكن لجهاز MediaController
إرسال أوامر مخصّصة خاصة بعنصر الوسائط
باستخدام MediaController.sendCustomCommand(SessionCommand, MediaItem, Bundle)
:
Kotlin
controller.sendCustomCommand(addToPlaylistButton.sessionCommand!!, mediaItem, Bundle.EMPTY)
Java
controller.sendCustomCommand( checkNotNull(addToPlaylistButton.sessionCommand), mediaItem, Bundle.EMPTY);