מדריך להעברת נתונים מ-AndroidX Media3

אפליקציות שמשתמשות כרגע בגרסה הנפרדת com.google.android.exoplayer2 הספרייה ו-androidx.media יועברו אל androidx.media3. כדאי להשתמש סקריפט ההעברה כדי להעביר קובצי build מסוג GRid, 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.
  • להשתמש ביכולות המתקדמות של MediaSession MediaController API.
  • אפשר לפרסם יכולות הפעלה באמצעות בקרת גישה פרטנית.
  • כדי לפשט את האפליקציה, מסירים את MediaSessionConnector PlayerNotificationManager
  • תאימות לאחור עם ממשקי API בצד הלקוח שתואמים למדיה (MediaBrowserCompat/MediaControllerCompat/MediaMetadataCompat)

ממשקי 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.

דרישות מוקדמות

  1. מוודאים שהפרויקט נמצא בבקרת מקור

    כדאי לוודא שאפשר לבטל בקלות שינויים שהוחלו על ידי כלי העברה שמכילים סקריפטים. אם עדיין לא הגדרת את הפרויקט שלך לבקרת מקור, עכשיו זה זמן מתאים להתחיל איתו. אם מסיבה כלשהי אינך רוצה לעשות זאת, צור עותק לגיבוי של הפרויקט שלך לפני התחלת ההעברה.

  2. עדכון האפליקציה

    • מומלץ לעדכן את הפרויקט כדי להשתמש ב- בגרסה העדכנית ביותר של ספריית ExoPlayer ומסירים קריאות ל-methods שהוצאו משימוש. אם בכוונתך להשתמש בסקריפט להעברה, עליכם להתאים לגרסה שאליה מתבצע העדכון, עם הגרסה שהסקריפט מטפל בה.

    • מעלים את compileSdkVersion של האפליקציה ל-32 לפחות.

    • שדרוג Gradle ואת הפלאגין של Android Studio Gradle שפועלת עם יחסי התלות המעודכנים שמוזכרים למעלה. עבור מופע:

      • גרסה של הפלאגין 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

שימוש בסקריפט ההעברה

  1. מורידים את סקריפט ההעברה מהתג של פרויקט ExoPlayer שימוש ב-GitHub בהתאם לגרסה שאליה עדכנתם את האפליקציה:

    curl -o media3-migration.sh \
      "https://raw.githubusercontent.com/google/ExoPlayer/r2.19.1/media3-migration.sh"
    
  2. יוצרים את קובץ ההפעלה של הסקריפט:

    chmod 744 media3-migration.sh
    
  3. כדי לקבל מידע על האפשרויות, אפשר להריץ את הסקריפט באמצעות --help.

  4. מריצים את הסקריפט עם -l כדי להציג את רשימת הקבצים שנבחרו עבור העברה (יש להשתמש ב--f כדי לאלץ את דף האפליקציה ללא אזהרות):

    ./media3-migration.sh -l -f /path/to/gradle/project/root
    
  5. מריצים את הסקריפט באמצעות -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:

  1. בודקים איך הסקריפט שינה את הקוד: שימוש בכלי הפרש ותיקון יכולות להיות בעיות אפשריות (כדאי לדווח על באג אם לדעתכם יש בסקריפט בעיה כללית שאירעה מבלי להעביר את האפשרות -f).
  2. כדי ליצור את הפרויקט: אפשר להשתמש ב-./gradlew clean build או ב-Android בוחרים באפשרות File > (קובץ >) סנכרון פרויקט עם קובצי Gradle ואז Build > ניקוי הפרויקט ואז Build > בניית פרויקט מחדש (מעקב אחר ה-build 'Build - Build Output' ב-Android Studio.

פעולות שמומלץ לבצע:

  1. פתרון בעיות שקשורות להבעת הסכמה לשגיאות בנוגע לשימוש בממשקי API לא יציבים.
  2. החלפת קריאות ל-API שהוצאו משימוש: השתמשו ב-API החלופי המוצע. מעבירים את הסמן מעל לאזהרה ב-Android Studio ומעיינים ב-JavaDoc של הסמל שהוצא משימוש כדי להבין במה להשתמש במקום בקריאה נתונה.
  3. מיון הדוחות של הייבוא: פותחים את הפרויקט ב-Android Studio ואז לוחצים לחיצה ימנית על צומת של תיקיית חבילה במציג הפרויקט ובוחרים לבצע אופטימיזציה של ייבוא בחבילות שמכילות את קובצי המקור שהשתנו.

מחליפים את MediaSessionConnector ב-androidx.media3.session.MediaSession

בעולם הקודם של MediaSessionCompat, MediaSessionConnector אחראי לסנכרון מצב הנגן עם מצב הסשן וקבלת פקודות מנאמני מידע שנדרשים להעניק גישה אל שיטות לנגן. עם AndroidX Media3, הפעולה הזו מתבצעת ישירות על ידי MediaSession ללא צורך במחבר.

  1. הסרת כל ההפניות והשימוש ב-MediaSessionConnector: אם השתמשתם הסקריפט האוטומטי להעברת מחלקות וחבילות של ExoPlayer, ואז סביר להניח שהסקריפט השאיר את הקוד שלך במצב לא הידור לגבי את MediaSessionConnector שאי אפשר לפענח. פלטפורמת Android Studio להציג את הקוד הפגום כשמנסים לבנות או להפעיל את האפליקציה.

  2. בקובץ build.gradle שבו שומרים על יחסי התלות, מוסיפים והתלות במודול הסשן של AndroidX Media3, ולהסיר את ליחסי התלות בדור קודם:

    implementation "androidx.media3:media3-session:1.4.1"
    
  3. מחליפים את MediaSessionCompat ב- androidx.media3.session.MediaSession.

  4. באתר הקוד שבו יצרתם את הגרסה הקודמת של MediaSessionCompat, משתמשים ב- androidx.media3.session.MediaSession.Builder כדי ליצור MediaSession מעבירים את הנגן כדי ליצור את הכלי ליצירת סשנים.

    val player = ExoPlayer.Builder(context).build()
    mediaSession = MediaSession.Builder(context, player)
        .setSessionCallback(MySessionCallback())
        .build()
    
  5. צריך להטמיע את MySessionCallback בהתאם לדרישות האפליקציה. לא חובה לעשות זאת. אם המיקום שרוצים לאפשר לבקרים להוסיף פריטי מדיה לנגן, להטמיע MediaSession.Callback.onAddMediaItems() היא משתמשת במגוון שיטות שיטות API מדור קודם שמוסיפות פריטי מדיה לנגן לצורך הפעלה שמתאימה לאחור. האיסור הזה כולל MediaController.set/addMediaItems() methods של בקר Media3, כמו וגם TransportControls.prepareFrom*/playFrom* ב-API מהדור הקודם. הטמעה לדוגמה של onAddMediaItems יכולה אפשר למצוא בPlaybackService של אפליקציית ההדגמה של הסשן.

  6. משחררים את סשן המדיה באתר הקוד שבו השמדתם את הסשן לפני ההעברה:

    mediaSession?.run {
      player.release()
      release()
      mediaSession = null
    }
    

הפונקציונליות של MediaSessionConnector ב-Media3

בטבלה הבאה מוצגים ממשקי ה-API של Media3 שמטפלים בפונקציונליות הוטמעו בעבר ב-MediaSessionConnector.

MediaSessionConnectorAndroidX Media3
CustomActionProvider MediaSession.Callback.onCustomCommand()/ MediaSession.setCustomLayout()
PlaybackPreparer MediaSession.Callback.onAddMediaItems() (השם prepare() נקרא באופן פנימי)
QueueNavigator ForwardingPlayer
QueueEditor MediaSession.Callback.onAddMediaItems()
RatingCallback MediaSession.Callback.onSetRating()
PlayerNotificationManager DefaultMediaNotificationProvider/ MediaNotification.Provider

העברה של MediaBrowserService אל MediaLibraryService

AndroidX Media3 מציג את MediaLibraryService שמחליף את MediaBrowserServiceCompat. ה-JavaDoc של MediaLibraryService וצוות ה-Super שלו MediaSessionService מספקים מבוא טוב ל-API, מודל תכנות אסינכרוני של השירות.

השדה MediaLibraryService תואם לאחור עם MediaBrowserService. אפליקציית לקוח שמשתמשת ב-MediaBrowserCompat או MediaControllerCompat, ממשיך לפעול ללא שינויים בקוד בעת החיבור אל MediaLibraryService. מבחינת הלקוחות, לא ברור אם האפליקציה באמצעות MediaLibraryService או MediaBrowserServiceCompat מדור קודם.

תרשים של רכיב אפליקציה עם שירות, פעילות ואפליקציות חיצוניות.
איור 1: סקירה כללית של רכיבי אפליקציית מדיה
  1. כדי שהתאימות לאחור תעבוד, צריך לרשום את שני השירותים ממשקים עם השירות שלכם ב-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>
    
  2. בקובץ build.gradle שבו שומרים על יחסי התלות, מוסיפים ותלויות בהטמעה של מודול הסשן של AndroidX Media3 להסיר את התלות הקודמת:

    implementation "androidx.media3:media3-session:1.4.1"
    
  3. לשנות את השירות כך שיקבל בירושה מMediaLibraryService במקום MediaBrowserService כפי שציינו קודם, MediaLibraryService תואם לגרסה הקודמת MediaBrowserService בהתאם לכך, ה-API הרחבה יותר של השירות ההצעות ללקוחות נשארות ללא שינוי. לכן, סביר להניח שאפליקציה יכולה לשמור את רוב הלוגיקה שנדרשת כדי להטמיע את MediaBrowserService ולהתאים אותו לMediaLibraryService החדש.

    ההבדלים העיקריים בהשוואה לדור הקודם MediaBrowserServiceCompat הם:

    • להטמיע את השיטות למחזור החיים של השירות: השיטות שצריך ניתנים לשינוי בשירות עצמו onCreate/onDestroy, כאשר מקצה/משחררת את הסשן בספרייה, את הנגן במשאבי אנוש. בנוסף לשיטות הרגילות של מחזור החיים של השירות, צריך לשנות את ברירת המחדל של onGetSession(MediaSession.ControllerInfo) כדי להחזיר MediaLibrarySession שנבנה ב-onCreate.

    • הטמעה של MediaLibraryService.MediaLibrarySessionCallback: פיתוח סשן מחייב MediaLibraryService.MediaLibrarySessionCallback מוטמע את ה-methods בפועל של ה-API של הדומיין. כך שבמקום לשנות שיטות API של בשירות מהדור הקודם, תבטלו את השיטות יש גם אפשרות MediaLibrarySession.Callback.

      לאחר מכן הקריאה החוזרת משמשת ליצירת MediaLibrarySession:

      mediaLibrarySession =
            MediaLibrarySession.Builder(this, player, MySessionCallback())
               .build()
      

      בממשק ה-API ניתן למצוא את ה-API המלא של MediaLibrarySessionCallback התיעוד.

    • הטמעה MediaSession.Callback.onAddMediaItems(): הקריאה החוזרת (callback) onAddMediaItems(MediaSession, ControllerInfo, List<MediaItem>) מילוי בקשות שיטות שונות של API, עדכניות ומדור קודם, שמוסיפות פריטי מדיה לנגן להפעלה באופן שתואם לאחור. האיסור הזה כולל MediaController.set/addMediaItems() methods של בקר Media3, וגם TransportControls.prepareFrom*/playFrom* ב-API מהדור הקודם. הטמעה לדוגמה של הקריאה החוזרת (callback) אפשר למצוא את בPlaybackService של אפליקציית ההדגמה של הסשן.

    • ב-AndroidX Media3 נעשה שימוש ב-androidx.media3.common.MediaItem במקום זאת של MediaBrowserCompat.MediaItem ו-MediaMetadataCompat. חלקים צריך לשנות בהתאם את הקוד שקשור למחלקות הקודמות או למפות אל Media3 MediaItem במקום זאת.

    • מודל התכנות האסינכרוני הכללי השתנה ל-Futures ב- בניגוד לגישת Result שניתן לנתק MediaBrowserServiceCompat הטמעת השירות שלך יכולה להחזיר אסינכרוניות ListenableFuture במקום לנתק תוצאה או החזרה של 'עתיד מיידי' כדי להחזיר ערך ישירות.

הסרת 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 האלה בטוחים לשימוש, ושגיאות השגיאות בקוד הן תוצר לוואי אחריות לתאימות בינארית. אם לא דורשים קוד בינארי מחמיר תאימות, ניתן לבטל שגיאות אלה באופן בטוח באמצעות @OptIn הערה.

רקע

גרסאות v1 או v2 של ExoPlayer לא סיפקו אחריות מחמירה לגבי תאימות בינארית. של הספרייה בין הגרסאות הבאות. הפלטפורמה של ExoPlayer API גדול משלב התכנון, כדי לאפשר לאפליקציות להתאים אישית כמעט כל היבט להפעלה. בגרסאות הבאות של ExoPlayer יופיע מדי פעם הסמל שינויי שמות או שינויי תוכנה אחרים שעלולים לגרום לכשלים (למשל שיטות נדרשות חדשות בממשקים). לחשבון ברוב המקרים אפשר לצמצם את הכשלים האלה על ידי הוספת הסמל החדש לצד הוצאה משימוש של הסמל הישן בכמה גרסאות, כדי לאפשר למפתחים זמן להעביר את השימושים שלהם, אבל זה לא תמיד היה אפשרי.

שינויי התוכנה האלה גרמו לשתי בעיות אצל המשתמשים ב-ExoPlayer v1 ו-v2 ספריות:

  1. שדרוג מגרסת ExoPlayer עלול לגרום להפסקת ההידור של הקוד.
  2. אפליקציה שתלויה ב-ExoPlayer גם באופן ישיר וגם דרך ביניים היה צריך לוודא ששני יחסי התלות הם אותה גרסה, אחרת, אי-תאימות בינארית עלולה לגרום לקריסות בזמן הריצה.

שיפורים ב-Media3

Media3 מבטיח תאימות בינארית לקבוצת משנה של פלטפורמת ה-API. חלקים שלא מבטיחים תאימות בינארית מסומנים @UnstableApi. כדי להבהיר את ההבחנה הזו, שימושים לא יציבים בסמלי API יוצרים שגיאת איתור שגיאות בקוד, אלא אם מוסיפים להם הערות עם @OptIn.

אחרי המעבר מ-ExpoPlayer v2 ל-Media3, ייתכן שתראו הרבה ממשקי API לא יציבים. שגיאות של איתור שגיאות בקוד. כתוצאה מכך, ייתכן שנראה ש-Media3 היא פחות יציבה. מאשר ExoPlayer גרסה 2. זה לא נכון. 'הבלתי יציב' לחלקים מה-Media3 API יש של היציבות כל פלטפורמת ה-API של ExoPlayer v2, שהפלטפורמה היציבה של Media3 API לא זמינה ב-ExoPlayer v2 הכול. ההבדל הוא פשוט ששגיאה של איתור שגיאות בקוד מתריעה בפניכם רמות היציבות.

טיפול בשגיאות של איתור שגיאות בקוד (lint) לא יציב ב-API

מידע על שגיאות שקשורות לתיקון שגיאות זמין בקטע שעוסק בפתרון בעיות. להוסיף הערות לשימושים ב-Java וב-Kotlin בממשקי API לא יציבים באמצעות @OptIn.

ממשקי API שהוצאו משימוש

יכול להיות שיהיו קריאות לממשקי API שהוצאו משימוש ב-Android אולפן. מומלץ להחליף קריאות כאלה בחלופה המתאימה. מעבירים את העכבר מעל הסמל כדי לראות את ה-JavaDoc שמציין באיזה API להשתמש במקום זאת.

צילום מסך: איך להציג JavaDoc עם חלופה לשיטה שהוצאה משימוש
איור 3: בהסבר הקצר על JavaDoc ב-Android Studio אפשר למצוא חלופה לכל סמל שהוצא משימוש.

דוגמאות קוד ואפליקציות להדגמה