Jetpack Media3 מגדיר ממשק Player
שמתאר את הפונקציונליות הבסיסית
להפעלה של קובצי וידאו ואודיו. הטמעת ברירת המחדל היא ExoPlayer
בממשק הזה ב-Media3. מומלץ להשתמש ב-ExoPlayer, מכיוון שהוא מספק
קבוצה מקיפה של תכונות שמכסות את רוב תרחישי השימוש של ההפעלה,
ניתנת להתאמה אישית כדי לטפל בכל תרחישי השימוש הנוספים. גם ExoPlayer
מפשט את הפיצול של המכשירים ושל מערכות ההפעלה כדי שהקוד יפעל באופן עקבי
בכל הסביבה העסקית של Android. ExoPlayer כולל:
- תמיכה בפלייליסטים
- תמיכה במגוון של שידורים מתקדמים וגמישים פורמטים
- תמיכה בהוספת מודעות בצד הלקוח ובצד השרת
- תמיכה בהפעלה שמוגנת באמצעות DRM
הדף הזה מסביר כמה מהשלבים העיקריים ביצירת הפעלה לפרטים נוספים, אפשר לעיין במדריכים המלאים 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()
של מחזור החיים ברמת API 24 ומעלה או onResume()
ה-method של מחזור החיים ברמת API 23 ומטה. לגבי שחקן שנכלל ב-Service
:
אפשר להכין אותה בonCreate()
.
שליטה בנגן
לאחר שהנגן מוכן, אפשר לשלוט בהפעלה באמצעות שיטות קריאה בנגן, למשל:
- הפקודה
play()
והפקודהpause()
כדי להתחיל ולהשהות את ההפעלה seekTo()
כדי לבצע מיקום בתוך פריט המדיה הנוכחיseekToNextMediaItem()
ו-seekToPreviousMediaItem()
כדי לנווט בפלייליסט
רכיבי ממשק משתמש כמו PlayerView
או PlayerControlView
יתעדכנו
בהתאם לשחקן.
שחרור הנגן
כדי להפעיל את הסרטון, עשויים להיות משאבים מוגבלים, כמו וידאו
ולכן חשוב לקרוא ל-release()
בנגן שלכם כדי לפנות משאבים כשהשחקן כבר לא נחוץ.
אם הנגן שלך נמצא בגרסה Activity
או Fragment
, משחררים אותו
שיטה onStop()
של מחזור החיים ברמת API 24 ומעלה או onPause()
ברמת API 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
עם Intent מסוג MediaSessionService
לסנן ולבקש את ההרשאה ל-FOREGROUND_SERVICE
כדי להריץ חזית
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
, כך שאפשר להשתמש
שיטות כמו play()
ו-pause()
לשליטה בהפעלה. דומה לרשימה אחרת
רכיבים, חשוב לזכור לשחרר את MediaController
כשהוא כבר לא פעיל
נדרש, כמו ה-method 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:
<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" />
הדוגמה שלמעלה כוללת מסנן Intent עבור MediaLibraryService
ולתאימות לאחור, גם הגרסה הקודמת של MediaBrowserService
.
מסנן Intent נוסף מאפשר אפליקציות לקוח באמצעות ה-API MediaBrowserCompat
לזהות את Service
.
MediaLibrarySession
מאפשר להציג את ספריית התוכן בעץ
עם שורש אחד, MediaItem
. כל MediaItem
בעץ יכול להכיל
כל מספר של צומתי MediaItem
צאצאים. אפשר למלא שורש אחר,
עץ שונה, בהתאם לבקשה של אפליקציית הלקוח. לדוגמה, העץ
לחזור ללקוח שמחפש רשימה של פריטי מדיה מומלצים,
מכילים את השורש MediaItem
ורמה אחת של צמתים מסוג MediaItem
צאצאים,
ואילו העץ שתחזירו לאפליקציית לקוח אחרת עשוי לייצג
את ספריית התוכן המלאה.
יצירת MediaLibrarySession
MediaLibrarySession
מרחיב את ממשק ה-API של MediaSession
כדי להוסיף ממשקי API לגלישה בתוכן. בהשוואה ל-
MediaSession
התקשרות חזרה,
הקריאה החוזרת MediaLibrarySession
מוסיפה שיטות כמו:
onGetLibraryRoot()
למקרים שבהם לקוח מבקש את הרמה הבסיסית (root)MediaItem
של עץ תוכןonGetChildren()
למקרים שבהם לקוח מבקש מהצאצאים שלMediaItem
בעץ התוכןonGetSearchResult()
למקרים שבהם לקוח מבקש תוצאות חיפוש מעץ התוכן שאילתה
שיטות רלוונטיות להתקשרות חזרה יכללו LibraryParams
אובייקט עם אותות נוספים לגבי סוג עץ התוכן שאפליקציית לקוח
שבו הוא מתעניין.