אפליקציות שמשתמשות כרגע בספרייה העצמאית com.google.android.exoplayer2
וב-androidx.media
צריכות לעבור ל-androidx.media3
. משתמשים בסקריפט ההעברה כדי להעביר קובצי build של Gradle, קובצי מקור של Java ו-Kotlin וקובצי פריסה של XML מ-ExoPlayer 2.19.1
אל AndroidX Media3 1.1.1
.
סקירה כללית
לפני שמבצעים את ההעברה, כדאי לעיין בקטעים הבאים כדי לקבל מידע נוסף על היתרונות של ממשקי ה-API החדשים, על ממשקי ה-API שצריך להעביר ועל הדרישות המוקדמות שהפרויקט של האפליקציה צריך לעמוד בהן.
למה כדאי לעבור ל-Jetpack Media3
- זהו הבית החדש של ExoPlayer, בעוד ש-
com.google.android.exoplayer2
הוצא משימוש. - גישה ל-Player API במרכיבים או בתהליכים שונים באמצעות
MediaBrowser
/MediaController
. - להשתמש ביכולות המורחבות של ה-API של
MediaSession
ושלMediaController
. - פרסום יכולות הפעלה באמצעות בקרת גישה פרטנית.
- מפשטים את האפליקציה על ידי הסרת
MediaSessionConnector
ו-PlayerNotificationManager
. - תאימות לאחור לממשקי API של לקוחות עם תאימות מדיה (
MediaBrowserCompat
/MediaControllerCompat
/MediaMetadataCompat
)
ממשקי Media API להעברה אל AndroidX Media3
- ExoPlayer והתוספים שלו
הכולל את כל המודולים של פרויקט ExoPlayer הקודם, מלבד המודול mediasession שהופסק. אפשר להעביר אפליקציות או מודולים שמסתמכים על חבילות ב-com.google.android.exoplayer2
באמצעות סקריפט ההעברה. - MediaSessionConnector (בהתאם לחבילות
androidx.media.*
שלandroidx.media:media:1.4.3+
)
מסירים אתMediaSessionConnector
ומשתמשים ב-androidx.media3.session.MediaSession
במקום זאת. - MediaBrowserServiceCompat (בהתאם לחבילות
androidx.media.*
שלandroidx.media:media:1.4.3+
)
מעבירים את תתי-המחלקות שלandroidx.media.MediaBrowserServiceCompat
אלandroidx.media3.session.MediaLibraryService
ומקודדים באמצעותMediaBrowserCompat.MediaItem
אלandroidx.media3.common.MediaItem
. - MediaBrowserCompat (בהתאם לחבילות
android.support.v4.media.*
שלandroidx.media:media:1.4.3+
)
מעבירים את קוד הלקוח באמצעותMediaBrowserCompat
אוMediaControllerCompat
כדי להשתמש ב-androidx.media3.session.MediaBrowser
עםandroidx.media3.common.MediaItem
.
דרישות מוקדמות
מוודאים שהפרויקט נמצא בפיקוח של מערכת לניהול גרסאות
חשוב לוודא שאפשר לבטל בקלות שינויים שהוחלו על ידי כלי העברה שמבוססים על סקריפטים. אם עדיין לא העברתם את הפרויקט למערכת בקרת הגרסאות, זה הזמן להתחיל. אם מסיבה כלשהי אתם לא רוצים לעשות זאת, תוכלו ליצור עותק לגיבוי של הפרויקט לפני שתתחילו את ההעברה.
עדכון האפליקציה
מומלץ לעדכן את הפרויקט כך שישתמש בגרסה האחרונה של ספריית ExoPlayer ולהסיר כל קריאה לשיטות שהוצאו משימוש. אם אתם מתכוונים להשתמש בסקריפט להעברה, עליכם להתאים את הגרסה שאליה אתם מעדכנים לגרסה שבה מטפל הסקריפט.
מעלים את הערך של compileSdkVersion של האפליקציה ל-32 לפחות.
משדרגים את Gradle ואת הפלאגין של Gradle ל-Android Studio לגרסה עדכנית שפועלת עם יחסי התלות המעודכנים שמפורטים למעלה. לדוגמה:
- גרסת הפלאגין של Android Gradle: 7.1.0
- גרסת Gradle: 7.4
מחליפים את כל הצהרות הייבוא עם תווים כלליים שמשתמשות באסימון כוכב (*), ומשתמשים בהצהרות ייבוא מוגדרות במלואן: מוחקים את הצהרות הייבוא עם תווים כלליים ומשתמשים ב-Android Studio כדי לייבא את ההצהרות המוגדרות במלואן (F2 - Alt/Enter, F2 - Alt/Enter, ...).
העברה מ-
com.google.android.exoplayer2.PlayerView
אלcom.google.android.exoplayer2.StyledPlayerView
. צריך לעשות זאת כי אין מקביל ל-com.google.android.exoplayer2.PlayerView
ב-AndroidX Media3.
העברת ExoPlayer עם תמיכה בסקריפטים
הסקריפט מאפשר לעבור מ-com.google.android.exoplayer2
למבנה החדש של החבילות והמודולים בקטע androidx.media3
. הסקריפט מחיל כמה בדיקות אימות על הפרויקט ומדפיס אזהרות אם האימות נכשל.
אחרת, הוא מחיל את המיפויים של הכיתות והחבילות ששינו את השם במשאבים של פרויקט Android gradle שנכתב ב-Java או ב-Kotlin.
usage: ./media3-migration.sh [-p|-c|-d|-v]|[-m|-l [-x <path>] [-f] PROJECT_ROOT]
PROJECT_ROOT: path to your project root (location of 'gradlew')
-p: list package mappings and then exit
-c: list class mappings (precedence over package mappings) and then exit
-d: list dependency mappings and then exit
-l: list files that will be considered for rewrite and then exit
-x: exclude the path from the list of file to be changed: 'app/src/test'
-m: migrate packages, classes and dependencies to AndroidX Media3
-f: force the action even when validation fails
-v: print the exoplayer2/media3 version strings of this script
-h, --help: show this help text
שימוש בסקריפט ההעברה
מורידים את סקריפט ההעברה מהתג של פרויקט ExoPlayer ב-GitHub, בהתאם לגרסה שאליה עדכנתם את האפליקציה:
curl -o media3-migration.sh \ "https://raw.githubusercontent.com/google/ExoPlayer/r2.19.1/media3-migration.sh"
הופכים את הסקריפט לניתן להפעלה:
chmod 744 media3-migration.sh
כדי לקבל מידע על האפשרויות, מריצים את הסקריפט באמצעות
--help
.מריצים את הסקריפט עם
-l
כדי להציג את רשימת הקבצים שנבחרו להעברה (משתמשים ב--f
כדי לאלץ את ההצגה ללא אזהרות):./media3-migration.sh -l -f /path/to/gradle/project/root
מריצים את הסקריפט עם
-m
כדי למפות חבילות, כיתות ומודולים ל-Media3. הפעלת הסקריפט עם האפשרות-m
תחיל את השינויים על הקבצים שנבחרו.- עצירה בשגיאת אימות בלי לבצע שינויים
./media3-migration.sh -m /path/to/gradle/project/root
- ביצוע מאולץ
אם הסקריפט מזהה הפרה של התנאים המוקדמים, אפשר לאלץ את ההעברה באמצעות הדגל
-f
:./media3-migration.sh -m -f /path/to/gradle/project/root
# list files selected for migration when excluding paths
./media3-migration.sh -l -x "app/src/test/" -x "service/" /path/to/project/root
# migrate the selected files
./media3-migration.sh -m -x "app/src/test/" -x "service/" /path/to/project/root
אחרי שמריצים את הסקריפט עם האפשרות -m
, מבצעים את השלבים הידניים הבאים:
- בודקים איך הסקריפט שינה את הקוד: משתמשים בכלי diff ומתקנים בעיות פוטנציאליות (כדאי לשלוח דיווח על באג אם לדעתכם יש בסקריפט בעיה כללית שנוצרה בלי להעביר את האפשרות
-f
). - מפעילים את ה-build של הפרויקט: משתמשים ב-
./gradlew clean build
או ב-Android Studio, בוחרים באפשרות File (קובץ) > Sync Project with Gradle Files (סנכרון הפרויקט עם קובצי Gradle), ואז באפשרות Build (יצירת build) > Clean project (ניקוי הפרויקט) ואז באפשרות Build (יצירת build) > Rebuild project (יצירת build מחדש) (אפשר לעקוב אחרי ה-build בכרטיסייה Build – Build Output (יצירת build – פלט ה-build) ב-Android Studio).
השלבים המומלצים להמשך:
- פותרים את הבעיה של הסכמה לקבלת שגיאות לגבי שימוש ב-API לא יציב.
- החלפת קריאות API שהוצאו משימוש: משתמשים ב-API החלופי שהוצעה. מעבירים את הסמן מעל האזהרה ב-Android Studio ומעיינים ב-JavaDoc של הסמל שהוצא משימוש כדי לברר במה להשתמש במקום בקריאה מסוימת.
- מיון של הצהרות הייבוא: פותחים את הפרויקט ב-Android Studio, לוחצים לחיצה ימנית על צומת של תיקיית חבילה בתצוגת הפרויקט ובוחרים באפשרות Optimize imports בחבילות שמכילות את קובצי המקור שהשתנו.
מחליפים את MediaSessionConnector
ב-androidx.media3.session.MediaSession
בעולם הקודם של MediaSessionCompat
, ה-MediaSessionConnector
היה אחראי לסנכרן את המצב של הנגן עם המצב של הסשן ולקבל פקודות מהבקרים שדרשו הענקת גישה לשיטות המתאימות של הנגן. ב-AndroidX Media3, הפעולה הזו מתבצעת על ידי MediaSession
ישירות, בלי צורך במחבר.
הסרת כל ההפניות והשימושים ב-MediaSessionConnector: אם השתמשתם בסקריפט האוטומטי כדי להעביר את הכיתות והחבילות של ExoPlayer, סביר להניח שהסקריפט השאיר את הקוד שלכם במצב שלא ניתן לבצע בו הידור לגבי
MediaSessionConnector
שלא ניתן לפתור. הקוד הפגום יוצג ב-Android Studio כשתנסו ליצור או להפעיל את האפליקציה.בקובץ
build.gradle
שבו אתם שומרים את יחסי התלות, מוסיפים תלות בהטמעה למודול הסשן של AndroidX Media3 ומסירים את התלות הקודמת:implementation "androidx.media3:media3-session:1.5.0"
מחליפים את הערך
MediaSessionCompat
ב-androidx.media3.session.MediaSession
.באתר הקוד שבו יצרתם את
MediaSessionCompat
הקודם, משתמשים ב-androidx.media3.session.MediaSession.Builder
כדי ליצורMediaSession
. מעבירים את הנגן כדי ליצור את הכלי ליצירת סשנים.val player = ExoPlayer.Builder(context).build() mediaSession = MediaSession.Builder(context, player) .setSessionCallback(MySessionCallback()) .build()
מטמיעים את
MySessionCallback
לפי הצורך באפליקציה. הפעולה הזו אופציונלית. אם רוצים לאפשר למכשירי הבקרה להוסיף פריטים של מדיה לנגן, צריך להטמיע אתMediaSession.Callback.onAddMediaItems()
. הוא מספק שיטות API שונות, קיימות וקודמות, שמוסיפות פריטים של מדיה לנגן להפעלה באופן תואם לאחור. זה כולל את השיטותMediaController.set/addMediaItems()
של הבקר Media3, וגם את השיטותTransportControls.prepareFrom*/playFrom*
של ה-API הקודם. הטמעה לדוגמה שלonAddMediaItems
מופיעה ב-PlaybackService
של אפליקציית הדגמה של הסשן.משחררים את סשן המדיה באתר הקוד שבו השמדתם את הסשן לפני ההעברה:
mediaSession?.run { player.release() release() mediaSession = null }
הפונקציונליות של MediaSessionConnector
ב-Media3
בטבלה הבאה מפורטים ממשקי ה-API של Media3 שמטפלים בפונקציות שהוטמעו בעבר ב-MediaSessionConnector
.
MediaSessionConnector | AndroidX Media3 |
---|---|
CustomActionProvider |
MediaSession.Callback.onCustomCommand()/
MediaSession.setCustomLayout() |
PlaybackPreparer |
MediaSession.Callback.onAddMediaItems()
(הקריאה ל-prepare() מתבצעת באופן פנימי)
|
QueueNavigator |
ForwardingSimpleBasePlayer |
QueueEditor |
MediaSession.Callback.onAddMediaItems() |
RatingCallback |
MediaSession.Callback.onSetRating() |
PlayerNotificationManager |
DefaultMediaNotificationProvider/
MediaNotification.Provider |
העברה של MediaBrowserService
אל MediaLibraryService
ב-AndroidX Media3 נוסף MediaLibraryService
שמחליף את MediaBrowserServiceCompat
. ב-JavaDoc של MediaLibraryService
ובסופר-קלאס שלו MediaSessionService
יש מבוא טוב ל-API ולמודל התכנות האסינכרוני של השירות.
ה-MediaLibraryService
תואם לאחור ל-MediaBrowserService
. אפליקציית לקוח שמשתמשת ב-MediaBrowserCompat
או ב-MediaControllerCompat
ממשיכה לפעול ללא שינויים בקוד כשהיא מתחברת ל-MediaLibraryService
. ללקוח ברור אם האפליקציה שלכם משתמשת ב-MediaLibraryService
או ב-MediaBrowserServiceCompat
מדור קודם.
כדי שתואם לאחור יפעל, צריך לרשום את שני ממשקי השירות בשירות ב-
AndroidManifest.xml
. כך הלקוח יכול למצוא את השירות שלכם לפי ממשק השירות הנדרש:<service android:name=".MusicService" android:exported="true"> <intent-filter> <action android:name="androidx.media3.session.MediaLibraryService"/> <action android:name="android.media.browse.MediaBrowserService" /> </intent-filter> </service>
בקובץ
build.gradle
שבו אתם שומרים את יחסי התלות, מוסיפים תלות הטמעה למודול הסשן של AndroidX Media3 ומסירים את תלות המורשת:implementation "androidx.media3:media3-session:1.5.0"
משנים את השירות כך שיירש מ-
MediaLibraryService
במקום מ-MediaBrowserService
. כפי שצוין קודם, ה-MediaLibraryService
תואם ל-MediaBrowserService
הקודם. לכן, ממשק ה-API הרחב יותר שהשירות מציע ללקוחות עדיין זהה. לכן סביר להניח שאפליקציה יכולה לשמור על רוב הלוגיקה שנדרשת להטמעתMediaBrowserService
ולהתאים אותה ל-MediaLibraryService
החדש.אלה ההבדלים העיקריים בהשוואה ל-
MediaBrowserServiceCompat
הקודם:הטמעת השיטות של מחזור החיים של השירות: השיטות שצריך לשנות בשירות עצמו הן
onCreate/onDestroy
, שבהן האפליקציה מקצה או משחררת את הסשן של הספרייה, את הנגן ומשאבים אחרים. בנוסף לשיטות הסטנדרטיות של מחזור החיים של השירות, האפליקציה צריכה לשנות אתonGetSession(MediaSession.ControllerInfo)
כדי להחזיר אתMediaLibrarySession
שנוצר ב-onCreate
.הטמעת MediaLibraryService.MediaLibrarySessionCallback: כדי ליצור סשן, צריך
MediaLibraryService.MediaLibrarySessionCallback
שמטמיע את שיטות ה-API בפועל של הדומיין. כך, במקום לשנות את שיטות ה-API של השירות הקודם, צריך לשנות את השיטות שלMediaLibrarySession.Callback
.לאחר מכן, הקריאה החוזרת משמשת ליצירת
MediaLibrarySession
:mediaLibrarySession = MediaLibrarySession.Builder(this, player, MySessionCallback()) .build()
ה-API המלא של MediaLibrarySessionCallback מופיע במסמכי התיעוד של ה-API.
הטמעת
MediaSession.Callback.onAddMediaItems()
: פונקציית ה-callbackonAddMediaItems(MediaSession, ControllerInfo, List<MediaItem>)
משמשת לשיטות API שונות, נוכחיות וקודמות, שמוסיפות פריטים של מדיה לנגן להפעלה באופן תואם לאחור. זה כולל את השיטותMediaController.set/addMediaItems()
של בקר Media3, וגם את השיטותTransportControls.prepareFrom*/playFrom*
של ה-API הקודם. דוגמה להטמעה של קריאה חוזרת מפורטת ב-PlaybackService
של אפליקציית הדגמה של הסשן.ב-AndroidX Media3 נעשה שימוש ב-
androidx.media3.common.MediaItem
במקום ב-MediaBrowserCompat.MediaItem וב-MediaMetadataCompat. חלקים מהקוד שמקושרים לכיתות הקודמות צריכים להשתנות בהתאם, או למפות ל-Media3MediaItem
במקום זאת.מודל התכנות האסינכרוני הכללי השתנה ל-
Futures
, בניגוד לגישה הנשלפת שלResult
ב-MediaBrowserServiceCompat
. הטמעת השירות יכולה להחזירListenableFuture
אסינכרוני במקום לנתק תוצאה או להחזיר Future מיידי כדי להחזיר ערך ישירות.
הסרת PlayerNotificationManager
MediaLibraryService
תומך בהתראות מדיה באופן אוטומטי, ואפשר להסיר את PlayerNotificationManager
כשמשתמשים ב-MediaLibraryService
או ב-MediaSessionService
.
אפליקציה יכולה להתאים אישית את ההתראה על ידי הגדרת MediaNotification.Provider
בהתאמה אישית ב-onCreate()
שמחליף את DefaultMediaNotificationProvider
. לאחר מכן, ה-MediaLibraryService
ידאג להפעיל את השירות בחזית לפי הצורך.
שינוי הערך של MediaLibraryService.updateNotification()
מאפשר לאפליקציה לקבל בעלות מלאה על פרסום ההתראה והפעלה/הפסקה של השירות בחזית, לפי הצורך.
העברת קוד לקוח באמצעות MediaBrowser
ב-AndroidX Media3, MediaBrowser
מטמיע את הממשקים MediaController/Player
, וניתן להשתמש בו כדי לשלוט בהפעלת המדיה בנוסף לגלישה בספריית המדיה. אם הייתם צריכים ליצור MediaBrowserCompat
ו-MediaControllerCompat
בעולם הקודם, תוכלו לעשות את אותו הדבר באמצעות שימוש רק ב-MediaBrowser
ב-Media3.
אפשר ליצור MediaBrowser
ולהמתין ליצירת החיבור לשירות:
scope.launch {
val sessionToken =
SessionToken(context, ComponentName(context, MusicService::class.java)
browser =
MediaBrowser.Builder(context, sessionToken))
.setListener(BrowserListener())
.buildAsync()
.await()
// Get the library root to start browsing the library.
root = browser.getLibraryRoot(/* params= */ null).await();
// Add a MediaController.Listener to listen to player state events.
browser.addListener(playerListener)
playerView.setPlayer(browser)
}
במאמר שליטה בהפעלה בסשן המדיה מוסבר איך יוצרים MediaController
כדי לשלוט בהפעלה ברקע.
שלבים נוספים ופינוי מקום
שגיאות API לא יציבות
אחרי ההעברה ל-Media3, יכול להיות שיופיעו שגיאות איתור שגיאות בקוד לגבי שימושים לא יציבים ב-API.
השימוש בממשקי ה-API האלה בטוח, ושגיאות ה-lint הן תוצר לוואי של ההתחייבויות החדשות שלנו לתאימות בינארית. אם לא נדרש תאימות בינארית קפדנית, אפשר לדכא את השגיאות האלה בבטחה באמצעות הערה @OptIn
.
רקע
גם ב-ExoPlayer v1 וגם ב-ExoPlayer v2 לא הייתה אחריות קפדנית לגבי תאימות הבינארית של הספרייה בין גרסאות עוקבות. ממשק ה-API של ExoPlayer גדול מאוד מעצם הגדרתו, כדי לאפשר לאפליקציות להתאים אישית כמעט כל היבט של ההפעלה. בגרסאות הבאות של ExoPlayer יתבצעו מדי פעם שינויים בשמות של סמלים או שינויים אחרים שמשביתים את הקוד (למשל, שיטות נדרשות חדשות בממשקים). ברוב המקרים, כדי לאפשר למפתחים להעביר את השימוש שלהם, הבעיות האלה טופלו על ידי הצגת הסמל החדש לצד ההוצאה משימוש של הסמל הישן בגרסאות מסוימות, אבל לא תמיד היה אפשר לעשות זאת.
השינויים האלה גרמו לשתי בעיות אצל משתמשי הספריות של ExoPlayer בגרסה 1 ובגרסה 2:
- שדרוג מגרסה לגרסת ExoPlayer עלול לגרום לכך שהקוד יפסיק להיערך.
- אפליקציה שהתבססה על ExoPlayer גם באופן ישיר וגם דרך ספרייה ביניים הייתה צריכה לוודא ששתי יחסי התלות היו באותה גרסה, אחרת אי-תאימות בינארית עלולה הייתה לגרום לקריסות בסביבת זמן הריצה.
שיפורים ב-Media3
Media3 מבטיחה תאימות בינארית לקבוצת משנה של ממשק ה-API. החלקים שלא מובטחת להם תאימות בינארית מסומנים ב-@UnstableApi
. כדי להבהיר את ההבדל הזה, שימוש בסמלי API לא יציבים יגרום לשגיאת איתור שגיאות בקוד (lint) אלא אם הם יסומנו ב-@OptIn
.
אחרי המעבר מ-ExoPlayer v2 ל-Media3, יכול להיות שתראו הרבה שגיאות לא יציבות של איתור שגיאות בקוד ב-API. לכן, יכול להיות שייראה ש-Media3 'פחות יציב' מ-ExoPlayer v2. זה לא המצב. החלקים 'הלא יציבים' של Media3 API הם ברמת יציבות זהה לזו של הכול בממשק ה-API של ExoPlayer v2, והערבויות של ממשק ה-API היציב של Media3 לא זמינות ב-ExoPlayer v2 בכלל. ההבדל הוא פשוט: עכשיו תקבלו התראות על רמות היציבות השונות כשיתגלה שגיאה באיתור שגיאות בקוד.
טיפול בשגיאות לא יציבות של איתור שגיאות בקוד ב-API
בקטע פתרון בעיות בשגיאות ה-lint האלה מוסבר איך להוסיף הערות לשימוש ב-Java וב-Kotlin בממשקי API לא יציבים באמצעות @OptIn
.
ממשקי API שהוצאו משימוש
יכול להיות שתבחינו בקריאות לממשקי API שהוצאו משימוש עם קו חוצה ב-Android Studio. מומלץ להחליף את הקריאות האלה באפשרות החלופית המתאימה. מעבירים את העכבר מעל הסמל כדי להציג את JavaDoc שמציין באיזה ממשק API להשתמש במקום זאת.
דוגמאות קוד ואפליקציות הדגמה
- אפליקציית הדגמה של סשן AndroidX Media3 (לנייד ול-WearOS)
- פעולות בהתאמה אישית
- התראה בממשק המשתמש של המערכת, MediaButton/BT
- שליטה בהפעלה של Google Assistant
- UAMP: Android Media Player (הסתעפות media3) (נייד, AutomotiveOS)
- התראה בממשק המשתמש של המערכת, לחצן מדיה/BT, המשך ההפעלה
- רכיבי UI להפעלה ב-Google Assistant או ב-WearOS
- AutomotiveOS: פקודה והרשמה בהתאמה אישית