אפליקציות מדיה מכילות לרוב אוספים של פריטי מדיה, שמסודרים בהיררכיה. לדוגמה, שירים באלבום או פרקים של תוכנית טלוויזיה בפלייליסט. ההיררכיה הזו של פריטי מדיה נקראת ספריית מדיה.
MediaLibraryService מספק API סטנדרטי להצגת ספריית המדיה שלכם ולגישה אליה. זה יכול להיות שימושי, למשל, כשמוסיפים תמיכה ב-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:
כדי להבטיח תאימות ללקוחות שמשתמשים בממשקי ה-API של הפלטפורמה להפעלת מדיה, מומלץ לכלול את
<action android:name="android.media.browse.MediaBrowserService"/>ברכיבintent-filter. Media3 מספקת אוטומטית תאימות לאחור לממשק השירות הזה.כדי להבטיח שהאפליקציות שמשתמשות ב-Media3 יוכלו לתקשר עם השירות שלכם באמצעות Media3 API, צריך לספק את
<action android:name="androidx.media3.session.MediaLibraryService"/>לצד אפשרות הפלטפורמה.
כך אפליקציות יכולות למצוא את השירות שלכם דרך PackageManager ולהתחבר ל-MediaBrowser דרך אחד מהממשקים האלה.
שימוש ב-MediaLibrarySession
ממשק MediaLibraryService API מצפה שספריית המדיה תהיה מובנית בפורמט של עץ, עם צומת בסיס יחיד וצמתים צאצאים שיכולים להיות ניתנים להפעלה או ניתנים לעיון.
MediaLibrarySession מרחיב את MediaSession API כדי להוסיף ממשקי API לעיון בתוכן. בהשוואה לMediaSession callback, ב-MediaLibrarySession callback נוספו שיטות כמו:
-
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);