راهنمای مهاجرت AndroidX Media3

برنامه‌هایی که در حال حاضر از کتابخانه مستقل com.google.android.exoplayer2 و androidx.media استفاده می‌کنند باید به androidx.media3 مهاجرت کنند. از اسکریپت مهاجرت برای انتقال فایل های ساخت gradle، فایل های منبع جاوا و Kotlin و فایل های طرح بندی XML از ExoPlayer 2.19.1 به AndroidX Media3 1.1.1 استفاده کنید.

نمای کلی

قبل از مهاجرت، بخش‌های زیر را مرور کنید تا در مورد مزایای APIهای جدید، APIهای انتقال و پیش نیازهایی که پروژه برنامه شما باید رعایت کند بیشتر بدانید.

چرا به Jetpack Media3 مهاجرت کنید

  • این خانه جدید ExoPlayer است، در حالی که com.google.android.exoplayer2 متوقف شده است.
  • با MediaBrowser / MediaController به API Player در بین اجزا/فرآیندها دسترسی داشته باشید.
  • از قابلیت های توسعه یافته 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+ )
    برای استفاده androidx.media3.session.MediaBrowser با androidx.media3.common.MediaItem ، کد سرویس گیرنده را با استفاده از MediaBrowserCompat یا MediaControllerCompat منتقل کنید.

پیش نیازها

  1. مطمئن شوید که پروژه شما تحت کنترل منبع است

    اطمینان حاصل کنید که می توانید به راحتی تغییرات اعمال شده توسط ابزارهای انتقال اسکریپت را برگردانید. اگر هنوز پروژه خود را تحت کنترل منبع ندارید، اکنون زمان خوبی برای شروع آن است. اگر به دلایلی نمی‌خواهید این کار را انجام دهید، قبل از شروع مهاجرت، یک نسخه پشتیبان از پروژه خود تهیه کنید.

  2. برنامه خود را به روز کنید

    • توصیه می‌کنیم پروژه خود را به‌روزرسانی کنید تا از جدیدترین نسخه کتابخانه ExoPlayer استفاده کنید و هرگونه تماس با روش‌های منسوخ را حذف کنید. اگر می‌خواهید از اسکریپت برای انتقال استفاده کنید ، باید نسخه‌ای را که به‌روزرسانی می‌کنید با نسخه‌ای که توسط اسکریپت مدیریت می‌شود مطابقت دهید.

    • کامپایلSdkVersion برنامه خود را به حداقل 32 افزایش دهید.

    • Gradle و افزونه Android Studio Gradle را به نسخه اخیر ارتقا دهید که با وابستگی های به روز شده از بالا کار می کند. به عنوان مثال:

      • نسخه پلاگین اندروید 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 را تسهیل می کند. این اسکریپت برخی از بررسی‌های اعتبارسنجی را روی پروژه شما اعمال می‌کند و در صورت عدم موفقیت اعتبار، هشدارها را چاپ می‌کند. در غیر این صورت، نگاشت کلاس ها و بسته های تغییر نام یافته را در منابع پروژه gradle اندروید نوشته شده در جاوا یا کاتلین اعمال می کند.

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. بررسی کنید که اسکریپت چگونه کد شما را تغییر داده است : از ابزار diff استفاده کنید و مشکلات احتمالی را برطرف کنید (اگر فکر می‌کنید اسکریپت دارای یک مشکل کلی است که بدون عبور از گزینه -f معرفی شده است، یک اشکال را در نظر بگیرید).
  2. پروژه را بسازید : یا از ./gradlew clean build استفاده کنید یا در اندروید استودیو File > Sync Project with Gradle Files را انتخاب کنید، سپس Build > Clean project و سپس Build > Rebuild project را انتخاب کنید (در تب «Build - Build Output» اندروید استودیو بر ساخت خود نظارت کنید.

مراحل پیشنهادی پیگیری:

  1. خطاهای مربوط به استفاده از APIهای ناپایدار را حل کنید.
  2. جایگزینی تماس‌های API منسوخ شده : از API جایگزین پیشنهادی استفاده کنید. نشانگر را روی اخطار در Android Studio نگه دارید و با JavaDoc نماد منسوخ شده مشورت کنید تا دریابید که به جای تماس معین از چه چیزی استفاده کنید.
  3. مرتب سازی عبارت های import : پروژه را در Android Studio باز کنید، سپس روی گره پوشه بسته در نمایشگر پروژه کلیک راست کرده و Optimize imports on بسته هایی که حاوی فایل های منبع تغییر یافته هستند را انتخاب کنید.

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.6.0"
    
  3. MediaSessionCompat را با androidx.media3.session.MediaSession جایگزین کنید.

  4. در سایت کدی که MediaSessionCompat قدیمی را ایجاد کرده‌اید، androidx.media3.session.MediaSession.Builder برای ساخت MediaSession استفاده کنید. برای ساخت Session Builder از بازیکن عبور دهید .

    val player = ExoPlayer.Builder(context).build()
    mediaSession = MediaSession.Builder(context, player)
        .setSessionCallback(MySessionCallback())
        .build()
    
  5. MySessionCallback را طبق نیاز برنامه خود پیاده کنید. این اختیاری است. اگر می خواهید به کنترلرها اجازه دهید آیتم های رسانه ای را به پخش کننده اضافه کنند، MediaSession.Callback.onAddMediaItems() را پیاده سازی کنید. این روش‌های مختلف API فعلی و قدیمی را ارائه می‌کند که آیتم‌های رسانه‌ای را به پخش کننده برای پخش به روشی سازگار با عقب اضافه می‌کند. این شامل متدهای MediaController.set/addMediaItems() کنترلر Media3 و همچنین متدهای TransportControls.prepareFrom*/playFrom* در API قدیمی است. یک نمونه از پیاده‌سازی onAddMediaItems را می‌توانید در PlaybackService برنامه نمایشی جلسه پیدا کنید.

  6. جلسه رسانه را در سایت کدی که قبل از انتقال جلسه خود را از بین برده اید، آزاد کنید:

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

قابلیت MediaSessionConnector در Media3

جدول زیر APIهای Media3 را نشان می‌دهد که عملکردهایی را که قبلاً در MediaSessionConnector پیاده‌سازی شده‌اند، مدیریت می‌کنند.

MediaSessionConnector AndroidX Media3
CustomActionProvider MediaSession.Callback.onCustomCommand()/ MediaSession.setMediaButtonPreferences()
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 قدیمی استفاده می کند.

نمودار مؤلفه برنامه با سرویس، فعالیت و برنامه های خارجی.
شکل 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.6.0"
    
  3. همانطور که قبلاً گفته MediaLibraryService MediaLibraryService MediaBrowserService MediaBrowserService سازگار است. بر این اساس، API گسترده‌تری که این سرویس به مشتریان ارائه می‌کند، همچنان یکسان است. بنابراین این احتمال وجود دارد که یک برنامه بتواند بیشتر منطق مورد نیاز برای اجرای MediaBrowserService را حفظ کند و آن را برای MediaLibraryService جدید تطبیق دهد.

    تفاوت های اصلی در مقایسه با MediaBrowserServiceCompat قدیمی به شرح زیر است:

    • روش‌های چرخه عمر سرویس را پیاده‌سازی کنید: روش‌هایی که باید روی خود سرویس نادیده گرفته شوند onCreate/onDestroy هستند، جایی که یک برنامه جلسه کتابخانه، پخش‌کننده و سایر منابع را اختصاص/آزاد می‌کند. علاوه بر روش‌های استاندارد چرخه عمر سرویس، یک برنامه باید onGetSession(MediaSession.ControllerInfo) لغو کند تا MediaLibrarySession ساخته شده در onCreate را برگرداند.

    • Implement MediaLibraryService.MediaLibrarySessionCallback: ایجاد یک جلسه به MediaLibraryService.MediaLibrarySessionCallback نیاز دارد که متدهای API دامنه واقعی را پیاده سازی می کند. بنابراین به جای نادیده گرفتن متدهای API سرویس قدیمی، روش های MediaLibrarySession.Callback را لغو می کنید.

      سپس از callback برای ساخت MediaLibrarySession استفاده می شود:

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

      API کامل MediaLibrarySessionCallback را در اسناد API پیدا کنید.

    • Implement MediaSession.Callback.onAddMediaItems() : پاسخ به تماس onAddMediaItems(MediaSession, ControllerInfo, List<MediaItem>) روش‌های مختلف API فعلی و قدیمی را ارائه می‌کند که آیتم‌های رسانه‌ای را به پخش کننده برای پخش به روشی سازگار با عقب اضافه می‌کند. این شامل متدهای MediaController.set/addMediaItems() کنترلر Media3 و همچنین متدهای TransportControls.prepareFrom*/playFrom* در API قدیمی است. نمونه‌ای از اجرای callback را می‌توانید در PlaybackService برنامه نمایشی جلسه پیدا کنید.

    • AndroidX Media3 به جای MediaBrowserCompat.MediaItem و MediaMetadataCompat از androidx.media3.common.MediaItem استفاده می کند. بخش‌هایی از کد شما که به کلاس‌های قدیمی مرتبط است باید بر اساس آن تغییر یابند یا به جای آن به Media3 MediaItem نگاشت شوند.

    • مدل برنامه‌نویسی ناهمزمان عمومی برخلاف رویکرد Result قابل جداسازی MediaBrowserServiceCompat به Futures تغییر کرد . پیاده‌سازی سرویس شما می‌تواند به جای جدا کردن یک نتیجه، یک 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 برای کنترل پخش در پس‌زمینه، به Control playback در جلسه رسانه نگاهی بیندازید.

مراحل بعدی و پاکسازی

خطاهای ناپایدار API

پس از مهاجرت به Media3، ممکن است خطاهای پرزهایی در مورد استفاده های ناپایدار API مشاهده کنید. استفاده از این API ها ایمن است و خطاهای پرز محصول جانبی تضمین های سازگاری باینری جدید ما هستند. اگر به سازگاری دقیق باینری نیاز ندارید، این خطاها را می توان با یک حاشیه نویسی @OptIn با خیال راحت سرکوب کرد.

پس زمینه

هیچ کدام ExoPlayer v1 یا v2 تضمین های دقیقی در مورد سازگاری باینری کتابخانه بین نسخه های بعدی ارائه نکردند. سطح API ExoPlayer از نظر طراحی بسیار بزرگ است تا به برنامه ها اجازه دهد تقریباً هر جنبه ای از پخش را سفارشی کنند. نسخه‌های بعدی ExoPlayer گاهی اوقات تغییر نام نمادها یا سایر تغییرات قطعی را معرفی می‌کنند (به عنوان مثال روش‌های جدید مورد نیاز در رابط‌ها). در بیشتر موارد، این شکستگی‌ها با معرفی نماد جدید در کنار حذف نماد قدیمی برای چند نسخه کاهش می‌یابد تا به توسعه‌دهندگان فرصت داده شود تا کاربردهای خود را تغییر دهند، اما این همیشه ممکن نبود.

این تغییرات شکسته منجر به دو مشکل برای کاربران کتابخانه‌های ExoPlayer v1 و v2 شد:

  1. ارتقا از نسخه ExoPlayer می تواند باعث توقف کامپایل کد شود.
  2. برنامه‌ای که هم مستقیماً و هم از طریق یک کتابخانه میانی به ExoPlayer وابسته بود باید اطمینان حاصل می‌کرد که هر دو وابستگی یک نسخه هستند، در غیر این صورت ناسازگاری‌های باینری می‌تواند منجر به خرابی زمان اجرا شود.

بهبود در Media3

Media3 سازگاری باینری را برای زیر مجموعه ای از سطح API تضمین می کند. قسمت هایی که سازگاری باینری را تضمین نمی کنند با @UnstableApi علامت گذاری شده اند. به منظور روشن کردن این تمایز، استفاده از نمادهای API ناپایدار یک خطای پرز ایجاد می کند، مگر اینکه با @OptIn حاشیه نویسی شده باشند.

پس از مهاجرت از ExoPlayer v2 به Media3، ممکن است خطاهای پرز ناپایدار API زیادی را مشاهده کنید. این ممکن است به نظر برسد که Media3 نسبت به ExoPlayer v2 «پایدارتر» است. اینطور نیست. بخش‌های «ناپایدار» Media3 API همان سطح پایداری کل سطح API ExoPlayer v2 را دارند و تضمین‌های سطح پایدار Media3 API اصلاً در ExoPlayer نسخه 2 موجود نیست. تفاوت در این است که اکنون یک خطای پرز به شما در مورد سطوح مختلف پایداری هشدار می دهد.

خطاهای پرز ناپایدار API را مدیریت کنید

برای جزئیات نحوه حاشیه نویسی استفاده از جاوا و کاتلین از APIهای ناپایدار با @OptIn به بخش عیب یابی در این خطاهای پرز مراجعه کنید.

API های منسوخ شده

ممکن است متوجه شوید که تماس‌ها با APIهای منسوخ شده در Android Studio انجام می‌شود. توصیه می کنیم چنین تماس هایی را با جایگزین مناسب جایگزین کنید. ماوس را روی نماد نگه دارید تا JavaDoc را ببینید که به شما می گوید از کدام API استفاده کنید.

اسکرین شات: نحوه نمایش JavaDoc با روش جایگزین منسوخ
شکل 3 : راهنمای ابزار JavaDoc در Android Studio یک جایگزین برای هر نماد منسوخ شده پیشنهاد می کند.

نمونه کد و برنامه های آزمایشی

  • برنامه نمایشی جلسه AndroidX Media3 (موبایل و WearOS)
    • اقدامات سفارشی
    • اعلان رابط کاربری سیستم، MediaButton/BT
    • کنترل پخش Google Assistant
  • UAMP: Android Media Player (شاخه media3) (موبایل، AutomotiveOS)
    • اعلان رابط کاربری سیستم، MediaButton/BT، ازسرگیری پخش
    • کنترل پخش Google Assistant/WearOS
    • AutomotiveOS: فرمان سفارشی و ورود به سیستم
،

برنامه‌هایی که در حال حاضر از کتابخانه مستقل com.google.android.exoplayer2 و androidx.media استفاده می‌کنند باید به androidx.media3 مهاجرت کنند. از اسکریپت مهاجرت برای انتقال فایل های ساخت gradle، فایل های منبع جاوا و Kotlin و فایل های طرح بندی XML از ExoPlayer 2.19.1 به AndroidX Media3 1.1.1 استفاده کنید.

نمای کلی

قبل از مهاجرت، بخش‌های زیر را مرور کنید تا در مورد مزایای APIهای جدید، APIهای انتقال و پیش نیازهایی که پروژه برنامه شما باید رعایت کند بیشتر بدانید.

چرا به Jetpack Media3 مهاجرت کنید

  • این خانه جدید ExoPlayer است، در حالی که com.google.android.exoplayer2 متوقف شده است.
  • با MediaBrowser / MediaController به API Player در بین اجزا/فرآیندها دسترسی داشته باشید.
  • از قابلیت های توسعه یافته 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+ )
    برای استفاده androidx.media3.session.MediaBrowser با androidx.media3.common.MediaItem ، کد سرویس گیرنده را با استفاده از MediaBrowserCompat یا MediaControllerCompat منتقل کنید.

پیش نیازها

  1. مطمئن شوید که پروژه شما تحت کنترل منبع است

    اطمینان حاصل کنید که می توانید به راحتی تغییرات اعمال شده توسط ابزارهای انتقال اسکریپت را برگردانید. اگر هنوز پروژه خود را تحت کنترل منبع ندارید، اکنون زمان خوبی برای شروع آن است. اگر به دلایلی نمی‌خواهید این کار را انجام دهید، قبل از شروع مهاجرت، یک نسخه پشتیبان از پروژه خود تهیه کنید.

  2. برنامه خود را به روز کنید

    • توصیه می‌کنیم پروژه خود را به‌روزرسانی کنید تا از جدیدترین نسخه کتابخانه ExoPlayer استفاده کنید و هرگونه تماس با روش‌های منسوخ را حذف کنید. اگر می‌خواهید از اسکریپت برای انتقال استفاده کنید ، باید نسخه‌ای را که به‌روزرسانی می‌کنید با نسخه‌ای که توسط اسکریپت مدیریت می‌شود مطابقت دهید.

    • کامپایلSdkVersion برنامه خود را به حداقل 32 افزایش دهید.

    • Gradle و افزونه Android Studio Gradle را به نسخه اخیر ارتقا دهید که با وابستگی های به روز شده از بالا کار می کند. به عنوان مثال:

      • نسخه پلاگین اندروید 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 را تسهیل می کند. این اسکریپت برخی از بررسی‌های اعتبارسنجی را روی پروژه شما اعمال می‌کند و در صورت عدم موفقیت اعتبار، هشدارها را چاپ می‌کند. در غیر این صورت، نگاشت کلاس ها و بسته های تغییر نام یافته را در منابع پروژه gradle اندروید نوشته شده در جاوا یا کاتلین اعمال می کند.

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. بررسی کنید که اسکریپت چگونه کد شما را تغییر داده است : از ابزار diff استفاده کنید و مشکلات احتمالی را برطرف کنید (اگر فکر می‌کنید اسکریپت دارای یک مشکل کلی است که بدون عبور از گزینه -f معرفی شده است، یک اشکال را در نظر بگیرید).
  2. پروژه را بسازید : یا از ./gradlew clean build استفاده کنید یا در اندروید استودیو File > Sync Project with Gradle Files را انتخاب کنید، سپس Build > Clean project و سپس Build > Rebuild project را انتخاب کنید (در تب «Build - Build Output» اندروید استودیو بر ساخت خود نظارت کنید.

مراحل پیشنهادی پیگیری:

  1. خطاهای مربوط به استفاده از APIهای ناپایدار را حل کنید.
  2. جایگزینی تماس‌های API منسوخ شده : از API جایگزین پیشنهادی استفاده کنید. نشانگر را روی اخطار در Android Studio نگه دارید و با JavaDoc نماد منسوخ شده مشورت کنید تا دریابید که به جای تماس معین از چه چیزی استفاده کنید.
  3. مرتب سازی عبارت های import : پروژه را در Android Studio باز کنید، سپس روی گره پوشه بسته در نمایشگر پروژه کلیک راست کرده و Optimize imports on بسته هایی که حاوی فایل های منبع تغییر یافته هستند را انتخاب کنید.

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.6.0"
    
  3. MediaSessionCompat را با androidx.media3.session.MediaSession جایگزین کنید.

  4. در سایت کدی که MediaSessionCompat قدیمی را ایجاد کرده‌اید، androidx.media3.session.MediaSession.Builder برای ساخت MediaSession استفاده کنید. برای ساخت Session Builder از بازیکن عبور دهید .

    val player = ExoPlayer.Builder(context).build()
    mediaSession = MediaSession.Builder(context, player)
        .setSessionCallback(MySessionCallback())
        .build()
    
  5. MySessionCallback را طبق نیاز برنامه خود پیاده کنید. این اختیاری است. اگر می خواهید به کنترلرها اجازه دهید آیتم های رسانه ای را به پخش کننده اضافه کنند، MediaSession.Callback.onAddMediaItems() را پیاده سازی کنید. این روش‌های مختلف API فعلی و قدیمی را ارائه می‌کند که آیتم‌های رسانه‌ای را به پخش کننده برای پخش به روشی سازگار با عقب اضافه می‌کند. این شامل متدهای MediaController.set/addMediaItems() کنترلر Media3 و همچنین متدهای TransportControls.prepareFrom*/playFrom* در API قدیمی است. یک نمونه از پیاده‌سازی onAddMediaItems را می‌توانید در PlaybackService برنامه نمایشی جلسه پیدا کنید.

  6. جلسه رسانه را در سایت کدی که قبل از انتقال جلسه خود را از بین برده اید، آزاد کنید:

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

قابلیت MediaSessionConnector در Media3

جدول زیر APIهای Media3 را نشان می‌دهد که عملکردهایی را که قبلاً در MediaSessionConnector پیاده‌سازی شده‌اند، مدیریت می‌کنند.

MediaSessionConnector AndroidX Media3
CustomActionProvider MediaSession.Callback.onCustomCommand()/ MediaSession.setMediaButtonPreferences()
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 قدیمی استفاده می کند.

نمودار مؤلفه برنامه با سرویس، فعالیت و برنامه های خارجی.
شکل 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.6.0"
    
  3. همانطور که قبلاً گفته MediaLibraryService MediaLibraryService MediaBrowserService MediaBrowserService سازگار است. بر این اساس، API گسترده‌تری که این سرویس به مشتریان ارائه می‌کند، همچنان یکسان است. بنابراین این احتمال وجود دارد که یک برنامه بتواند بیشتر منطق مورد نیاز برای اجرای MediaBrowserService را حفظ کند و آن را برای MediaLibraryService جدید تطبیق دهد.

    تفاوت های اصلی در مقایسه با MediaBrowserServiceCompat قدیمی به شرح زیر است:

    • روش‌های چرخه عمر سرویس را پیاده‌سازی کنید: روش‌هایی که باید روی خود سرویس نادیده گرفته شوند onCreate/onDestroy هستند، جایی که یک برنامه جلسه کتابخانه، پخش‌کننده و سایر منابع را اختصاص/آزاد می‌کند. علاوه بر روش‌های استاندارد چرخه عمر سرویس، یک برنامه باید onGetSession(MediaSession.ControllerInfo) لغو کند تا MediaLibrarySession ساخته شده در onCreate را برگرداند.

    • Implement MediaLibraryService.MediaLibrarySessionCallback: ایجاد یک جلسه به MediaLibraryService.MediaLibrarySessionCallback نیاز دارد که متدهای API دامنه واقعی را پیاده سازی می کند. بنابراین به جای نادیده گرفتن متدهای API سرویس قدیمی، روش های MediaLibrarySession.Callback را لغو می کنید.

      سپس از callback برای ساخت MediaLibrarySession استفاده می شود:

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

      API کامل MediaLibrarySessionCallback را در اسناد API پیدا کنید.

    • Implement MediaSession.Callback.onAddMediaItems() : پاسخ به تماس onAddMediaItems(MediaSession, ControllerInfo, List<MediaItem>) روش‌های مختلف API فعلی و قدیمی را ارائه می‌کند که آیتم‌های رسانه‌ای را به پخش کننده برای پخش به روشی سازگار با عقب اضافه می‌کند. این شامل متدهای MediaController.set/addMediaItems() کنترلر Media3 و همچنین متدهای TransportControls.prepareFrom*/playFrom* در API قدیمی است. نمونه‌ای از اجرای callback را می‌توانید در PlaybackService برنامه نمایشی جلسه پیدا کنید.

    • AndroidX Media3 به جای MediaBrowserCompat.MediaItem و MediaMetadataCompat از androidx.media3.common.MediaItem استفاده می کند. بخش‌هایی از کد شما که به کلاس‌های قدیمی مرتبط است باید بر اساس آن تغییر یابند یا به جای آن به Media3 MediaItem نگاشت شوند.

    • مدل برنامه‌نویسی ناهمزمان عمومی برخلاف رویکرد Result قابل جداسازی MediaBrowserServiceCompat به Futures تغییر کرد . پیاده‌سازی سرویس شما می‌تواند به جای جدا کردن یک نتیجه، یک 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 ها برای استفاده بی خطر هستند و خطاهای خطی محصول جانبی ضمانت سازگاری باینری جدید ما است. اگر به سازگاری باینری دقیق احتیاج ندارید ، این خطاها با یک حاشیه نویسی @OptIn می توانند با خیال راحت سرکوب شوند.

پس زمینه

هیچ یک از سیارات سیاره V1 یا V2 تضمین های دقیق در مورد سازگاری باینری کتابخانه بین نسخه های بعدی ارائه نمی دهند. سطح API Exoplayer با طراحی بسیار بزرگ است ، به منظور این امکان که برنامه ها بتوانند تقریباً هر جنبه ای از پخش را سفارشی کنند. نسخه های بعدی از سیارات سیارات گاه به گاه تغییر نام های نماد یا سایر تغییرات شکستن را معرفی می کند (به عنوان مثال روشهای جدید مورد نیاز در رابط ها). در بیشتر موارد ، این شکستگی ها با معرفی نماد جدید در کنار استهلاک نماد قدیمی برای چند نسخه کاهش یافته است تا به توسعه دهندگان اجازه دهد تا کاربردهای خود را مهاجرت کنند ، اما این همیشه امکان پذیر نبود.

این تغییرات شکستن منجر به دو مشکل برای کاربران کتابخانه های سیارات سیارات V1 و V2 شد:

  1. به روزرسانی از نسخه سیارات سیارات می تواند باعث شود که کد از کامپایل متوقف شود.
  2. برنامه ای که به سیارات فراتر و چه از طریق یک کتابخانه واسطه بستگی دارد ، باید اطمینان حاصل کند که هر دو وابستگی همان نسخه هستند ، در غیر این صورت ناسازگاری های باینری می تواند منجر به تصادفات زمان شود.

پیشرفت در Media3

Media3 سازگاری باینری را برای زیر مجموعه ای از سطح API تضمین می کند. قطعاتی که سازگاری باینری را تضمین نمی کنند با @UnstableApi مشخص می شوند. به منظور روشن کردن این تمایز ، استفاده از نمادهای API ناپایدار خطای خط ایجاد می کند مگر اینکه با @OptIn حاشیه نویسی شوند.

پس از مهاجرت از سیارات سیارات V2 به Media3 ، ممکن است خطاهای ناپایدار API را مشاهده کنید. این ممکن است به نظر برسد که Media3 نسبت به سیارات V2 "پایدار" کمتری دارد. اینطور نیست. قسمت های "ناپایدار" API Media3 دارای همان سطح ثبات سطح سطح سیارات سیارات V2 API هستند و ضمانت های سطح API پایدار Media3 به هیچ وجه در سیارات سیارات V2 در دسترس نیست. تفاوت این است که اکنون یک خطای خطی شما را به سطوح مختلف ثبات هشدار می دهد.

خطاهای ناپایدار API را برطرف کنید

برای جزئیات بیشتر در مورد چگونگی حاشیه نویسی جاوا و کوتلین از API های ناپایدار با @OptIn ، بخش عیب یابی را در این خطاهای خط مشاهده کنید.

API های منسوخ شده

ممکن است توجه داشته باشید که تماس های مربوط به API های مستهجن در استودیوی اندرویدی مورد ضرب و شتم قرار گرفته است. توصیه می کنیم چنین تماس هایی را با گزینه جایگزین مناسب جایگزین کنید. برای دیدن Javadoc که می گوید API به جای آن از کدام API استفاده می کند ، روی نماد حرکت کنید.

تصویر: نحوه نمایش Javadoc با جایگزین روش مستهلک
شکل 3 : ابزار ابزار Javadoc در Android Studio گزینه ای را برای هر نماد مستهجن پیشنهاد می کند.

نمونه های کد و برنامه های نسخه ی نمایشی

  • برنامه نمایشی جلسه Androidx Media3 (موبایل و Wearos)
    • اقدامات سفارشی
    • اطلاع رسانی UI سیستم ، MediaButton/BT
    • کنترل پخش دستیار Google
  • UAMP: Android Media Player (Branch Media3) (موبایل ، اتومبیل)
    • اطلاع رسانی UI سیستم ، MediaButton/BT ، از سرگیری پخش
    • دستیار Google/کنترل پخش WearOS
    • AutomotiveOS: فرمان سفارشی و ورود به سیستم
،

برنامه هایی که در حال حاضر از کتابخانه مستقل com.google.android.exoplayer2 استفاده می کنند و androidx.media باید به androidx.media3 مهاجرت کنند. از اسکریپت مهاجرت برای مهاجرت فایلهای Gradle Build ، فایل های منبع جاوا و Kotlin و پرونده های طرح بندی XML از Exoplayer 2.19.1 به Androidx Media3 1.1.1 استفاده کنید.

نمای کلی

قبل از مهاجرت ، بخش های زیر را مرور کنید تا در مورد مزایای API های جدید ، API ها برای مهاجرت و پیش نیازهای پروژه برنامه شما باید بیشتر بدانید.

چرا به Jetpack Media3 مهاجرت کنید

  • این خانه جدید Exoplayer است ، در حالی که com.google.android.exoplayer2 قطع می شود.
  • دسترسی به API پخش کننده در بین مؤلفه ها / فرآیندها با MediaBrowser / MediaController .
  • از قابلیت های گسترده MediaSession و MediaController API استفاده کنید.
  • قابلیت های پخش را با کنترل دسترسی ریز دانه تبلیغ کنید.
  • برنامه خود را با حذف MediaSessionConnector و PlayerNotificationManager ساده کنید.
  • به عقب سازگار با API های مشتری رسانه ای (رسانه ای) ( MediaBrowserCompat / MediaControllerCompat / MediaMetadataCompat )

API های رسانه ای برای مهاجرت به Androidx Media3

  • سیارات فراتر و پسوند آن
    این شامل تمام ماژول های پروژه سیارات سیاره میراث به جز ماژول MediaSession است که قطع شده است. برنامه ها یا ماژول ها بسته به بسته های موجود در com.google.android.exoplayer2 با اسکریپت مهاجرت قابل انتقال هستند.
  • MediaSessionConnector (بسته به androidx.media.* بسته های androidx.media:media:1.4.3+ : 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+ )
    برای استفاده از androidx.media3.session.MediaBrowser با androidx.media3.common.MediaItem ، کد مشتری را با استفاده از MediaBrowserCompat یا MediaControllerCompat مهاجرت کنید.

پیش نیازها

  1. اطمینان حاصل کنید که پروژه شما تحت کنترل منبع است

    اطمینان حاصل کنید که می توانید به راحتی تغییرات اعمال شده توسط ابزارهای مهاجرت اسکریپت را برگردانید. اگر هنوز پروژه خود را تحت کنترل منبع ندارید ، اکنون زمان خوبی برای شروع با آن است. اگر به دلایلی نمی خواهید این کار را انجام دهید ، قبل از شروع مهاجرت ، یک نسخه پشتیبان از پروژه خود تهیه کنید.

  2. برنامه خود را به روز کنید

    • ما توصیه می کنیم پروژه خود را به روز کنید تا از جدیدترین نسخه کتابخانه سیارات سیارات استفاده کنید و هرگونه تماس با روشهای مستهجن را حذف کنید. اگر قصد استفاده از اسکریپت را برای مهاجرت دارید ، باید نسخه ای را که به روز می کنید با نسخه ای که توسط اسکریپت انجام شده است مطابقت دهید.

    • CompilesDkversion برنامه خود را حداقل 32 افزایش دهید.

    • Gradle Gradle و Android Studio Gradle Plugin را به نسخه اخیر که با وابستگی های به روز شده از بالا کار می کند ، ارتقا دهید . به عنوان مثال:

      • نسخه افزونه Android Gradle: 7.1.0
      • نسخه Gradle: 7.4
    • تمام اظهارات واردات Wildcard را که از Asterix (*) استفاده می کنند جایگزین کنید و از بیانیه های وارداتی کاملاً واجد شرایط استفاده کنید: بیانیه های واردات Wildcard را حذف کنید و از 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 وجود ندارد.

مهاجرت سیارات سیاره را با پشتیبانی از اسکریپت مهاجرت کنید

این اسکریپت حرکت از com.google.android.exoplayer2 به بسته و ساختار جدید ماژول تحت androidx.media3 را تسهیل می کند. اسکریپت برخی از بررسی های اعتبار سنجی را در پروژه شما اعمال می کند و در صورت عدم موفقیت اعتبار ، هشدارها را چاپ می کند. در غیر این صورت ، نقشه های کلاس ها و بسته های تغییر نام در منابع یک پروژه Gradle Android که در جاوا یا کوتلین نوشته شده است ، استفاده می کند.

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. اسکریپت مهاجرت را از برچسب پروژه سیارات سیارات در 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 Studio استفاده کنید .

مراحل پیگیری توصیه شده:

  1. تصمیم گیری در مورد خطاهای مربوط به استفاده از API های ناپایدار را حل کنید.
  2. تماس های API مستهلک شده را جایگزین کنید : از API جایگزین پیشنهادی استفاده کنید. نشانگر را بیش از هشدار در استودیوی اندروید نگه دارید و با Javadoc از نماد مستهجن مشورت کنید تا دریابید که به جای یک تماس معین از چه چیزی استفاده کنید.
  3. اظهارات واردات را مرتب کنید : پروژه را در Android Studio باز کنید ، سپس روی یک گره پوشه بسته در Viewer Project کلیک راست کرده و واردات را در بسته هایی که حاوی پرونده های منبع تغییر یافته هستند ، بهینه کنید.

MediaSessionConnector را با androidx.media3.session.MediaSession جایگزین کنید

در دنیای میراث MediaSessionCompat ، MediaSessionConnector مسئول همگام سازی وضعیت بازیکن با وضعیت جلسه و دریافت دستورات از کنترل کننده هایی بود که به روش های مناسب بازیکن نیاز داشتند. با Androidx Media3 ، این کار توسط MediaSession مستقیماً بدون نیاز به کانکتور انجام می شود.

  1. همه منابع و استفاده از MediaSessionConnector را حذف کنید: اگر از اسکریپت خودکار برای مهاجرت کلاس ها و بسته های سیاخلندی استفاده کرده اید ، احتمالاً اسکریپت کد شما را در یک وضعیت غیرقابل کنترل در مورد MediaSessionConnector که قابل حل نیست ، رها کرده است. Android Studio هنگام تلاش برای ساخت یا شروع برنامه ، کد شکسته را به شما نشان می دهد.

  2. در پرونده build.gradle که وابستگی های خود را حفظ می کنید ، به ماژول جلسه Androidx Media3 وابسته به اجرای آن اضافه کنید و وابستگی میراث را حذف کنید:

    implementation "androidx.media3:media3-session:1.6.0"
    
  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() کنترلر Media3 ، و همچنین TransportControls.prepareFrom*/playFrom* روش های API میراث است. اجرای نمونه ای از onAddMediaItems را می توان در PlaybackService برنامه نسخه ی نمایشی جلسه مشاهده کرد.

  6. جلسه رسانه ای را در سایت کد منتشر کنید که در آن جلسه خود را قبل از مهاجرت از بین بردید:

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

عملکرد MediaSessionConnector در Media3

جدول زیر API های Media3 را نشان می دهد که عملکردی را که قبلاً در MediaSessionConnector اجرا شده بود ، کنترل می کنند.

دستگاه سنجش رسانه AndroidX Media3
CustomActionProvider MediaSession.Callback.onCustomCommand()/ MediaSession.setMediaButtonPreferences()
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 of MediaLibraryService و Super Class 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.6.0"
    
  3. خدمات خود را تغییر دهید MediaLibraryService به جای MediaBrowserService داخلی به ارث برسید ، سرویس MediaLibraryService با Legacy MediaBrowserService سازگار است. بر این اساس ، API گسترده تر که این سرویس به مشتری ارائه می دهد هنوز یکسان است. بنابراین این احتمال وجود دارد که یک برنامه بتواند بیشتر منطق مورد نیاز برای اجرای MediaBrowserService را حفظ کند و آن را برای خدمات جدید MediaLibraryService تطبیق دهد.

    تفاوتهای اصلی در مقایسه با میراث MediaBrowserServiceCompat به شرح زیر است:

    • روشهای چرخه زندگی خدمات را پیاده سازی کنید: روشهایی که باید در این سرویس نادیده گرفته شوند onCreate/onDestroy هستند ، جایی که یک برنامه جلسه کتابخانه ، پخش کننده و سایر منابع را اختصاص می دهد. علاوه بر روشهای استاندارد چرخه زندگی ، یک برنامه برای بازگشت MediaLibrarySession که در onCreate ساخته شده است ، باید onGetSession(MediaSession.ControllerInfo) غلبه کند.

    • پیاده سازی MedialibraryService.MedialibrarySessionCallback: ایجاد یک جلسه نیاز به یک MediaLibraryService.MediaLibrarySessionCallback دارد. medialibrarySessionCallback که روشهای واقعی API دامنه را پیاده سازی می کند. بنابراین به جای غلبه بر روشهای API از خدمات میراث ، به جای آن روشهای MediaLibrarySession.Callback را نادیده می گیرید.

      پس از آن از پاسخ به تماس برای ساخت MediaLibrarySession استفاده می شود:

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

      API کامل از MedialibrarySessionCallback را در مستندات API پیدا کنید.

    • پیاده سازی MediaSession.Callback.onAddMediaItems() : پاسخ به تماس onAddMediaItems(MediaSession, ControllerInfo, List<MediaItem>) در خدمت روشهای مختلف API فعلی و میراث است که موارد رسانه ای را به پخش کننده برای پخش به صورت سازگار با عقب اضافه می کند. این شامل روشهای MediaController.set/addMediaItems() کنترلر Media3 ، و همچنین TransportControls.prepareFrom*/playFrom* روش های API میراث است. اجرای نمونه از پاسخ به تماس را می توان در PlaybackService برنامه نسخه ی نمایشی جلسه مشاهده کرد.

    • Androidx Media3 به جای MediaBrowserCompat.MediaItem و MediametAdatacompat از androidx.media3.common.MediaItem استفاده می کند. بخش هایی از کد شما که به کلاسهای میراث گره خورده است ، باید مطابق آن تغییر کنند یا به جای آن به Media3 MediaItem نقشه برداری شوند.

    • مدل برنامه نویسی Futures عمومی بر خلاف رویکرد Result جداکننده MediaBrowserServiceCompat به آینده تغییر یافت. اجرای خدمات شما می تواند به جای جدا کردن نتیجه ، یک ListenableFuture ناهمزمان را برگرداند یا آینده ای نزدیک را برگرداند تا مستقیماً یک مقدار را برگرداند .

حذف playernotificationManager

سرویس MediaLibraryService از اعلان های رسانه ای به طور خودکار پشتیبانی می کند و در هنگام استفاده از یک MediaLibraryService یا MediaSessionService می توان PlayerNotificationManager حذف کرد.

یک برنامه می تواند با تنظیم یک 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 تضمین های دقیق در مورد سازگاری باینری کتابخانه بین نسخه های بعدی ارائه نمی دهند. سطح API Exoplayer با طراحی بسیار بزرگ است ، به منظور این امکان که برنامه ها بتوانند تقریباً هر جنبه ای از پخش را سفارشی کنند. نسخه های بعدی از سیارات سیارات گاه به گاه تغییر نام های نماد یا سایر تغییرات شکستن را معرفی می کند (به عنوان مثال روشهای جدید مورد نیاز در رابط ها). در بیشتر موارد ، این شکستگی ها با معرفی نماد جدید در کنار استهلاک نماد قدیمی برای چند نسخه کاهش یافته است تا به توسعه دهندگان اجازه دهد تا کاربردهای خود را مهاجرت کنند ، اما این همیشه امکان پذیر نبود.

این تغییرات شکستن منجر به دو مشکل برای کاربران کتابخانه های سیارات سیارات V1 و V2 شد:

  1. به روزرسانی از نسخه سیارات سیارات می تواند باعث شود که کد از کامپایل متوقف شود.
  2. برنامه ای که به سیارات فراتر و چه از طریق یک کتابخانه واسطه بستگی دارد ، باید اطمینان حاصل کند که هر دو وابستگی همان نسخه هستند ، در غیر این صورت ناسازگاری های باینری می تواند منجر به تصادفات زمان شود.

پیشرفت در Media3

Media3 سازگاری باینری را برای زیر مجموعه ای از سطح API تضمین می کند. قطعاتی که سازگاری باینری را تضمین نمی کنند با @UnstableApi مشخص می شوند. به منظور روشن کردن این تمایز ، استفاده از نمادهای API ناپایدار خطای خط ایجاد می کند مگر اینکه با @OptIn حاشیه نویسی شوند.

پس از مهاجرت از سیارات سیارات V2 به Media3 ، ممکن است خطاهای ناپایدار API را مشاهده کنید. این ممکن است به نظر برسد که Media3 نسبت به سیارات V2 "پایدار" کمتری دارد. اینطور نیست. قسمت های "ناپایدار" API Media3 دارای همان سطح ثبات سطح سطح سیارات سیارات V2 API هستند و ضمانت های سطح API پایدار Media3 به هیچ وجه در سیارات سیارات V2 در دسترس نیست. تفاوت این است که اکنون یک خطای خطی شما را به سطوح مختلف ثبات هشدار می دهد.

خطاهای ناپایدار API را برطرف کنید

برای جزئیات بیشتر در مورد چگونگی حاشیه نویسی جاوا و کوتلین از API های ناپایدار با @OptIn ، بخش عیب یابی را در این خطاهای خط مشاهده کنید.

API های منسوخ شده

ممکن است توجه داشته باشید که تماس های مربوط به API های مستهجن در استودیوی اندرویدی مورد ضرب و شتم قرار گرفته است. توصیه می کنیم چنین تماس هایی را با گزینه جایگزین مناسب جایگزین کنید. برای دیدن Javadoc که می گوید API به جای آن از کدام API استفاده می کند ، روی نماد حرکت کنید.

تصویر: نحوه نمایش Javadoc با جایگزین روش مستهلک
شکل 3 : ابزار ابزار Javadoc در Android Studio گزینه ای را برای هر نماد مستهجن پیشنهاد می کند.

نمونه های کد و برنامه های نسخه ی نمایشی

  • برنامه نمایشی جلسه Androidx Media3 (موبایل و Wearos)
    • اقدامات سفارشی
    • اطلاع رسانی UI سیستم ، MediaButton/BT
    • کنترل پخش دستیار Google
  • UAMP: Android Media Player (Branch Media3) (موبایل ، اتومبیل)
    • اطلاع رسانی UI سیستم ، MediaButton/BT ، از سرگیری پخش
    • دستیار Google/کنترل پخش WearOS
    • AutomotiveOS: فرمان سفارشی و ورود به سیستم
،

برنامه هایی که در حال حاضر از کتابخانه مستقل com.google.android.exoplayer2 استفاده می کنند و androidx.media باید به androidx.media3 مهاجرت کنند. از اسکریپت مهاجرت برای مهاجرت فایلهای Gradle Build ، فایل های منبع جاوا و Kotlin و پرونده های طرح بندی XML از Exoplayer 2.19.1 به Androidx Media3 1.1.1 استفاده کنید.

نمای کلی

قبل از مهاجرت ، بخش های زیر را مرور کنید تا در مورد مزایای API های جدید ، API ها برای مهاجرت و پیش نیازهای پروژه برنامه شما باید بیشتر بدانید.

چرا به Jetpack Media3 مهاجرت کنید

  • این خانه جدید Exoplayer است ، در حالی که com.google.android.exoplayer2 قطع می شود.
  • دسترسی به API پخش کننده در بین مؤلفه ها / فرآیندها با MediaBrowser / MediaController .
  • از قابلیت های گسترده MediaSession و MediaController API استفاده کنید.
  • قابلیت های پخش را با کنترل دسترسی ریز دانه تبلیغ کنید.
  • برنامه خود را با حذف MediaSessionConnector و PlayerNotificationManager ساده کنید.
  • به عقب سازگار با API های مشتری رسانه ای (رسانه ای) ( MediaBrowserCompat / MediaControllerCompat / MediaMetadataCompat )

API های رسانه ای برای مهاجرت به Androidx Media3

  • سیارات فراتر و پسوند آن
    این شامل تمام ماژول های پروژه سیارات سیاره میراث به جز ماژول MediaSession است که قطع شده است. برنامه ها یا ماژول ها بسته به بسته های موجود در com.google.android.exoplayer2 با اسکریپت مهاجرت قابل انتقال هستند.
  • MediaSessionConnector (بسته به androidx.media.* بسته های androidx.media:media:1.4.3+ : 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+ )
    برای استفاده از androidx.media3.session.MediaBrowser با androidx.media3.common.MediaItem ، کد مشتری را با استفاده از MediaBrowserCompat یا MediaControllerCompat مهاجرت کنید.

پیش نیازها

  1. اطمینان حاصل کنید که پروژه شما تحت کنترل منبع است

    اطمینان حاصل کنید که می توانید به راحتی تغییرات اعمال شده توسط ابزارهای مهاجرت اسکریپت را برگردانید. اگر هنوز پروژه خود را تحت کنترل منبع ندارید ، اکنون زمان خوبی برای شروع با آن است. اگر به دلایلی نمی خواهید این کار را انجام دهید ، قبل از شروع مهاجرت ، یک نسخه پشتیبان از پروژه خود تهیه کنید.

  2. برنامه خود را به روز کنید

    • ما توصیه می کنیم پروژه خود را به روز کنید تا از جدیدترین نسخه کتابخانه سیارات سیارات استفاده کنید و هرگونه تماس با روشهای مستهجن را حذف کنید. اگر قصد استفاده از اسکریپت را برای مهاجرت دارید ، باید نسخه ای را که به روز می کنید با نسخه ای که توسط اسکریپت انجام شده است مطابقت دهید.

    • CompilesDkversion برنامه خود را حداقل 32 افزایش دهید.

    • Gradle Gradle و Android Studio Gradle Plugin را به نسخه اخیر که با وابستگی های به روز شده از بالا کار می کند ، ارتقا دهید . به عنوان مثال:

      • نسخه افزونه Android Gradle: 7.1.0
      • نسخه Gradle: 7.4
    • تمام اظهارات واردات Wildcard را که از Asterix (*) استفاده می کنند جایگزین کنید و از بیانیه های وارداتی کاملاً واجد شرایط استفاده کنید: بیانیه های واردات Wildcard را حذف کنید و از 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 وجود ندارد.

مهاجرت سیارات سیاره را با پشتیبانی از اسکریپت مهاجرت کنید

این اسکریپت حرکت از com.google.android.exoplayer2 به بسته و ساختار جدید ماژول تحت androidx.media3 را تسهیل می کند. اسکریپت برخی از بررسی های اعتبار سنجی را در پروژه شما اعمال می کند و در صورت عدم موفقیت اعتبار ، هشدارها را چاپ می کند. در غیر این صورت ، نقشه های کلاس ها و بسته های تغییر نام در منابع یک پروژه Gradle Android که در جاوا یا کوتلین نوشته شده است ، استفاده می کند.

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. اسکریپت مهاجرت را از برچسب پروژه سیارات سیارات در 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 Studio استفاده کنید .

مراحل پیگیری توصیه شده:

  1. تصمیم گیری در مورد خطاهای مربوط به استفاده از API های ناپایدار را حل کنید.
  2. تماس های API مستهلک شده را جایگزین کنید : از API جایگزین پیشنهادی استفاده کنید. نشانگر را بیش از هشدار در استودیوی اندروید نگه دارید و با Javadoc از نماد مستهجن مشورت کنید تا دریابید که به جای یک تماس معین از چه چیزی استفاده کنید.
  3. اظهارات واردات را مرتب کنید : پروژه را در Android Studio باز کنید ، سپس روی یک گره پوشه بسته در Viewer Project کلیک راست کرده و واردات را در بسته هایی که حاوی پرونده های منبع تغییر یافته هستند ، بهینه کنید.

MediaSessionConnector را با androidx.media3.session.MediaSession جایگزین کنید

در دنیای میراث MediaSessionCompat ، MediaSessionConnector مسئول همگام سازی وضعیت بازیکن با وضعیت جلسه و دریافت دستورات از کنترل کننده هایی بود که به روش های مناسب بازیکن نیاز داشتند. با Androidx Media3 ، این کار توسط MediaSession مستقیماً بدون نیاز به کانکتور انجام می شود.

  1. همه منابع و استفاده از MediaSessionConnector را حذف کنید: اگر از اسکریپت خودکار برای مهاجرت کلاس ها و بسته های سیاخلندی استفاده کرده اید ، احتمالاً اسکریپت کد شما را در یک وضعیت غیرقابل کنترل در مورد MediaSessionConnector که قابل حل نیست ، رها کرده است. Android Studio هنگام تلاش برای ساخت یا شروع برنامه ، کد شکسته را به شما نشان می دهد.

  2. در پرونده build.gradle که وابستگی های خود را حفظ می کنید ، به ماژول جلسه Androidx Media3 وابسته به اجرای آن اضافه کنید و وابستگی میراث را حذف کنید:

    implementation "androidx.media3:media3-session:1.6.0"
    
  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() کنترلر Media3 ، و همچنین TransportControls.prepareFrom*/playFrom* روش های API میراث است. اجرای نمونه ای از onAddMediaItems را می توان در PlaybackService برنامه نسخه ی نمایشی جلسه مشاهده کرد.

  6. جلسه رسانه ای را در سایت کد منتشر کنید که در آن جلسه خود را قبل از مهاجرت از بین بردید:

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

عملکرد MediaSessionConnector در Media3

جدول زیر API های Media3 را نشان می دهد که عملکردی را که قبلاً در MediaSessionConnector اجرا شده بود ، کنترل می کنند.

دستگاه سنجش رسانه AndroidX Media3
CustomActionProvider MediaSession.Callback.onCustomCommand()/ MediaSession.setMediaButtonPreferences()
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 of MediaLibraryService و Super Class 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.6.0"
    
  3. خدمات خود را تغییر دهید MediaLibraryService به جای MediaBrowserService داخلی به ارث برسید ، سرویس MediaLibraryService با Legacy MediaBrowserService سازگار است. بر این اساس ، API گسترده تر که این سرویس به مشتری ارائه می دهد هنوز یکسان است. بنابراین این احتمال وجود دارد که یک برنامه بتواند بیشتر منطق مورد نیاز برای اجرای MediaBrowserService را حفظ کند و آن را برای خدمات جدید MediaLibraryService تطبیق دهد.

    تفاوتهای اصلی در مقایسه با میراث MediaBrowserServiceCompat به شرح زیر است:

    • روشهای چرخه زندگی خدمات را پیاده سازی کنید: روشهایی که باید در این سرویس نادیده گرفته شوند onCreate/onDestroy هستند ، جایی که یک برنامه جلسه کتابخانه ، پخش کننده و سایر منابع را اختصاص می دهد. In addition to standard service life-cycle methods, an app needs to override onGetSession(MediaSession.ControllerInfo) to return the MediaLibrarySession that was built in onCreate .

    • Implement MediaLibraryService.MediaLibrarySessionCallback: Building a session requires a MediaLibraryService.MediaLibrarySessionCallback that implements the actual domain API methods. So instead of overriding API methods of the legacy service, you will override the methods of the MediaLibrarySession.Callback instead.

      The callback is then used to build the MediaLibrarySession :

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

      Find the full API of the MediaLibrarySessionCallback in the API documentation.

    • Implement MediaSession.Callback.onAddMediaItems() : The callback onAddMediaItems(MediaSession, ControllerInfo, List<MediaItem>) serves various current and legacy API methods that add media items to the player for playback in a backwards compatible way. This includes the MediaController.set/addMediaItems() methods of the Media3 controller, as well as the TransportControls.prepareFrom*/playFrom* methods of the legacy API. A sample implementation of the callback can be found in the PlaybackService of the session demo app .

    • AndroidX Media3 is using androidx.media3.common.MediaItem instead of MediaBrowserCompat.MediaItem and MediaMetadataCompat . Parts of your code tied to the legacy classes need to be changed accordingly or map to the Media3 MediaItem instead.

    • The general asynchronous programming model changed to Futures in contrast to the detachable Result approach of the MediaBrowserServiceCompat . Your service implementation can return an asynchronous ListenableFuture instead of detaching a result or return an immediate Future to directly return a value .

Remove PlayerNotificationManager

The MediaLibraryService supports media notifications automatically and the PlayerNotificationManager can be removed when using a MediaLibraryService or MediaSessionService .

An app can customize the notification by setting a custom MediaNotification.Provider in onCreate() that replaces the DefaultMediaNotificationProvider . The MediaLibraryService then takes care of starting the service in the foreground as required.

By overriding MediaLibraryService.updateNotification() an app can further take full ownership of posting a notification and starting/stopping the service in the foreground as required.

Migrate client code using a MediaBrowser

With AndroidX Media3, a MediaBrowser implements the MediaController/Player interfaces and can be used to control media playback besides browsing the media library. If you had to create a MediaBrowserCompat and a MediaControllerCompat in the legacy world, you can do the same by only using the MediaBrowser in Media3.

A MediaBrowser can be built and await for the connection to the service being established:

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)
}

Take a look into Control playback in the media session to learn how to create a MediaController for controlling playback in the background.

Further steps and clean up

Unstable API errors

After migrating to Media3, you may see lint errors about unstable API usages. These APIs are safe to use and the lint errors are a by-product of our new binary compatibility guarantees. If you don't require strict binary compatibility, these errors can be safely suppressed with an @OptIn annotation.

پس زمینه

Neither ExoPlayer v1 or v2 provided strict guarantees about binary compatibility of the library between subsequent versions. The ExoPlayer API surface is very large by design, in order to allow apps to customize nearly every aspect of playback. Subsequent versions of ExoPlayer would occasionally introduce symbol renames or other breaking changes (eg new required methods on interfaces). In most cases these breakages were mitigated by introducing the new symbol alongside deprecating the old symbol for a few versions, to allow developers time to migrate their usages, but this wasn't always possible.

These breaking changes resulted in two problems for users of the ExoPlayer v1 and v2 libraries:

  1. An upgrade from to the ExoPlayer version could cause code to stop compiling.
  2. An app that depended on ExoPlayer both directly and via an intermediate library had to ensure that both dependencies were the same version, otherwise binary incompatibilities could result in runtime crashes.

Improvements in Media3

Media3 guarantees binary compatibility for a subset of the API surface. The parts that don't guarantee binary compatibility are marked with @UnstableApi . In order to make this distinction clear, usages of unstable API symbols generate a lint error unless they are annotated with @OptIn .

After migrating from ExoPlayer v2 to Media3, you may see a lot of unstable API lint errors. This may make it seem like Media3 is 'less stable' than ExoPlayer v2. اینطور نیست. The 'unstable' parts of the Media3 API have the same level of stability as the whole of the ExoPlayer v2 API surface, and the guarantees of the stable Media3 API surface are not available in ExoPlayer v2 at all. The difference is simply that a lint error now alerts you to the different levels of stability.

Handle unstable API lint errors

See the troubleshooting section on these lint errors for details on how to annotate Java and Kotlin usages of unstable APIs with @OptIn .

API های منسوخ شده

You may notice that calls to deprecated APIs are struck-through in Android Studio. We recommend replacing such calls with the appropriate alternative. Hover over the symbol to see the JavaDoc that tells which API to use instead.

Screenshot: How to display JavaDoc with alternative of deprecated method
Figure 3 : JavaDoc tooltip in Android Studio suggests an alternative for any deprecated symbol.

Code samples and demo apps