برنامههایی که درحالحاضر از کتابخانه مستقل com.google.android.exoplayer2
و androidx.media استفاده میکنند باید به androidx.media3 منتقل شوند. از
اسکریپت انتقال برای انتقال فایلهای ساخت gradle، فایلهای منبع جاوا و
Kotlin، و فایلهای چیدمان XML از ExoPlayer
2.19.1 به AndroidX Media3 1.1.1 استفاده کنید.
نمای کلی
قبلاز انتقال، بخشهای زیر را مرور کنید تا درباره مزایای میاناهای برنامهسازی کاربردی جدید، میاناهای برنامهسازی کاربردی برای انتقال، و پیشنیازهایی که پروژه برنامهتان باید داشته باشد بیشتر بدانید.
چرا باید به Jetpack Media3 مهاجرت کرد
- این خانه جدید ExoPlayer است، درحالیکه
com.google.android.exoplayer2متوقف شده است. - دسترسی به Player API در سراسر مؤلفهها/فرایندها با
MediaBrowser/MediaController. - از قابلیتهای گسترشیافته میانای برنامهسازی کاربردی
MediaSessionوMediaControllerاستفاده کنید. - قابلیتهای بازپخش را با کنترل دسترسی دقیق تبلیغ کنید.
- با برداشتن
MediaSessionConnectorوPlayerNotificationManager، برنامهتان را ساده کنید. - سازگار با نسخههای قدیمی با میاناهای برنامهسازی کاربردی کارخواه media-compat
(
MediaBrowserCompat/MediaControllerCompat/MediaMetadataCompat)
میاناهای برنامهسازی کاربردی رسانه برای انتقال به 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 برنامهتان را حداقل به ۳۲ افزایش دهید.
Gradle و افزایه Android Studio Gradle را به نسخه جدیدی ارتقا دهید که با وابستگیهای بهروزشده بالا کار میکند. برای مثال:
- نسخه افزایه Android Gradle: ۷.۱.۰
- نسخه Gradle: ۷.۴
همه عبارتهای وارد کردن با نویسه عام را که از ستاره (*) استفاده میکنند جایگزین کنید و از عبارتهای وارد کردن کاملاً واجدشرایط استفاده کنید: عبارتهای وارد کردن با نویسه عام را حذف کنید و از 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 Android نوشتهشده در 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معرفی شده است، یک اشکال ثبت کنید). - ساختن پروژه: از
./gradlew clean buildاستفاده کنید یا در «استودیو Android» فایل > همگامسازی پروژه با فایلهای Gradle، سپس ساختن > پاک کردن پروژه، و سپس ساختن > بازساختن پروژه را انتخاب کنید (ساختن خود را در برگه «ساختن - خروجی ساختن» در «استودیو Android» پایش کنید).
مراحل پیگیری توصیهشده:
- موافقت کردن با خطاهای مربوط به استفاده از میاناهای برنامهسازی کاربردی ناپایدار را حل کنید.
- جایگزین کردن فراخوانیهای API منسوخشده: از API جایگزین پیشنهادی استفاده کنید. اشارهگر را روی هشدار در «استودیو Android» نگه دارید و با JavaDoc نماد منسوخشده مشورت کنید تا متوجه شوید بهجای تماس دادهشده از چه چیزی استفاده کنید.
- مرتبسازی دستورهای وارد کردن: پروژه را در «استودیو Android» باز کنید، سپس روی گره پوشه بسته در نمایشگر پروژه کلیک راست کنید و بهینهسازی وارد کردنها را در بستههایی که حاوی فایلهای منبع تغییریافته هستند انتخاب کنید.
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.11.1"MediaSessionCompatرا باandroidx.media3.session.MediaSessionجایگزین کنید.در سایت کدی که
MediaSessionCompatقدیمی را ایجاد کردهاید، ازandroidx.media3.session.MediaSession.Builderبرای ساختنMediaSessionاستفاده کنید. پخشکننده را ارسال کنید تا سازنده جلسه ساخته شود.کاتلین
val player = ExoPlayer.Builder(context).build() mediaSession = MediaSession.Builder(context, player).setCallback(MySessionCallback()).build()
جاوا
ExoPlayer player = new ExoPlayer.Builder(context).build(); mediaSession = new MediaSession.Builder(context, player).setCallback(new MySessionCallback()).build();
MySessionCallbackرا طبق نیاز برنامهتان پیادهسازی کنید. این کار اختیاری است. اگر میخواهید به کنترلکنندهها اجازه دهید موارد رسانهای را به پخشکننده اضافه کنند،MediaSession.Callback.onAddMediaItems()را پیادهسازی کنید. این کلاس روشهای مختلف فعلی و قدیمی میانای برنامهسازی کاربردی را ارائه میدهد که موارد رسانهای را برای بازپخش به روشی سازگار با نسخههای قدیمی به پخشکننده اضافه میکنند. این شامل روشهایMediaController.set/addMediaItems()کنترلکننده Media3 و همچنین روشهایTransportControls.prepareFrom*/playFrom*میانای برنامهسازی کاربردی قدیمی میشود. نمونهای از پیادهسازیonAddMediaItemsرا میتوانید درPlaybackServiceبرنامه نمایشی جلسه پیدا کنید.جلسه رسانه را در سایت کد که در آن جلسه را قبلاز انتقال ازبین بردید، منتشر کنید:
کاتلین
mediaSession?.run { player.release() release() mediaSession = null }
جاوا
if (mediaSession != null) { mediaSession.getPlayer().release(); mediaSession.release(); mediaSession = null; }
عملکرد MediaSessionConnector در Media3
جدول زیر میاناهای برنامهسازی کاربردی 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 قدیمی.
برای اینکه سازگاری با نسخه قدیمی کار کند، باید هر دو میانای سرویس را با سرویس خود در
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.11.1"سرویس خود را تغییر دهید تا بهجای
MediaBrowserServiceازMediaLibraryServiceارثبری کند. همانطور که قبلاً گفته شد،MediaLibraryServiceباMediaBrowserServiceقدیمی سازگار است. بنابراین، میانای برنامهسازی کاربردی گستردهتری که سرویس به کارخواهان ارائه میدهد همچنان یکسان است. بنابراین احتمالاً برنامه میتواند بیشتر منطق لازم برای پیادهسازیMediaBrowserServiceرا حفظ کند و آن را برایMediaLibraryServiceجدید تطبیق دهد.تفاوتهای اصلی در مقایسه با
MediaBrowserServiceCompatقدیمی به شرح زیر است:پیادهسازی روشهای چرخه عمر سرویس: روشهایی که باید در خود سرویس لغو شوند عبارتند از
onCreate/onDestroy، که در آن برنامه جلسه کتابخانه، پخشکننده، و سایر منابع را اختصاص میدهد/آزاد میکند. علاوهبر روشهای استاندارد چرخه عمر سرویس، برنامه بایدonGetSession(MediaSession.ControllerInfo)را لغو کند تاMediaLibrarySessionساختهشده درonCreateرا برگرداند.پیادهسازی MediaLibraryService.MediaLibrarySessionCallback: ساختن جلسه به
MediaLibraryService.MediaLibrarySessionCallbackنیاز دارد که روشهای میانای برنامهسازی کاربردی دامنه واقعی را پیادهسازی میکند. بنابراین بهجای لغو کردن روشهای میانای برنامهسازی کاربردی سرویس قدیمی، روشهایMediaLibrarySession.Callbackرا لغو خواهید کرد.سپس از فراخوانی برگشتی برای ساختن
MediaLibrarySessionاستفاده میشود:کاتلین
mediaLibrarySession = MediaLibrarySession.Builder(context, player, MySessionCallback()).build()
جاوا
mediaLibrarySession = new MediaLibrarySession.Builder(context, player, new MySessionCallback()).build();
میانای برنامهسازی کاربردی کامل MediaLibrarySessionCallback را در اسناد میانای برنامهسازی کاربردی پیدا کنید.
پیادهسازی
MediaSession.Callback.onAddMediaItems(): فراخوانی برگشتیonAddMediaItems(MediaSession, ControllerInfo, List<MediaItem>)روشهای مختلف میانای برنامهسازی کاربردی فعلی و قدیمی را که موارد رسانهای را برای بازپخش به روش سازگار با نسخههای قدیمی به پخشکننده اضافه میکنند ارائه میدهد. این شامل روشهایMediaController.set/addMediaItems()کنترلکننده Media3، و همچنین روشهایTransportControls.prepareFrom*/playFrom*میانای برنامهسازی کاربردی قدیمی میشود. نمونهای از پیادهسازی callback را میتوانید درPlaybackServiceبرنامه نمایشی جلسه پیدا کنید.AndroidX Media3 بهجای MediaBrowserCompat.MediaItem و MediaMetadataCompat از
androidx.media3.common.MediaItemاستفاده میکند. بخشهایی از کد شما که به کلاسهای قدیمی مرتبط است باید بهطور مناسب تغییر کند یا بهجای آن به 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")) browser = MediaBrowser.Builder(context, sessionToken) .setListener(BrowserListener()) .buildAsync() .await() }
جاوا
SessionToken sessionToken = new SessionToken(context, new ComponentName(context, "MusicService")); ListenableFuture<MediaBrowser> browserFuture = new MediaBrowser.Builder(context, sessionToken) .setListener(new BrowserListener()) .buildAsync();
به
کنترل بازپخش در جلسه رسانه
نگاهی بیندازید تا با نحوه ایجاد MediaController برای کنترل بازپخش در پسزمینه آشنا شوید.
مراحل بعدی و پاکسازی
خطاهای میانای برنامهسازی کاربردی ناپایدار
پساز انتقال به Media3، ممکن است خطاهای lint درباره استفادههای ناپایدار از API ببینید.
استفاده از این میاناهای برنامهسازی کاربردی ایمن است و خطاهای lint محصول جانبی تضمینهای جدید سازگاری دودویی ما است. اگر به سازگاری دودویی دقیق نیاز ندارید،
میتوانید این خطاها را با حاشیهنویسی @OptIn
بهطور ایمن سرکوب کنید.
پسزمینه
هیچکدام از ExoPlayer نسخه ۱ یا ۲ تضمینهای دقیقی درباره سازگاری دودویی کتابخانه بین نسخههای بعدی ارائه نمیدهند. سطح ExoPlayer API بهطور عمدی بسیار بزرگ طراحی شده است تا برنامهها بتوانند تقریباً هر جنبهای از بازپخش را سفارشیسازی کنند. نسخههای بعدی ExoPlayer گاهی اوقات تغییر نام نماد یا تغییرات شکننده دیگری را معرفی میکنند (مثلاً روشهای جدید موردنیاز در میاناهای کاربری). در بیشتر موارد، این شکستگیها با معرفی نماد جدید در کنار منسوخ کردن نماد قدیمی برای چند نسخه کاهش یافت تا توسعهدهندگان زمان کافی برای انتقال استفادههای خود داشته باشند، اما این امر همیشه ممکن نبود.
این تغییرات ناسازگار منجر به دو مشکل برای کاربران کتابخانههای ExoPlayer نسخه ۱ و ۲ شد:
- ارتقا دادن به نسخه ExoPlayer میتواند باعث شود کد کامپایل نشود.
- برنامهای که هم بهطور مستقیم و هم ازطریق کتابخانه واسطه به ExoPlayer وابسته بود، باید مطمئن میشد که هر دو وابستگی از یک نسخه هستند، درغیراینصورت ناسازگاریهای دودویی میتوانست منجر به ازکارافتادن زمان اجرا شود.
بهبودهای Media3
Media3 سازگاری دودویی را برای زیرمجموعهای از سطح میانای برنامهسازی کاربردی تضمین میکند. بخشهایی که سازگاری دودویی را تضمین نمیکنند با @UnstableApi علامتگذاری شدهاند. برای روشن کردن این تمایز، استفاده از نمادهای ناپایدار
میانای برنامهسازی کاربردی خطای lint ایجاد میکند، مگراینکه با @OptIn حاشیهنویسی شده باشند.
پساز انتقال از ExoPlayer نسخه ۲ به Media3، ممکن است خطاهای lint زیادی در API ناپایدار مشاهده کنید. این ممکن است باعث شود Media3 «پایداری کمتری» نسبتبه ExoPlayer نسخه ۲ داشته باشد. اینطور نیست. بخشهای «ناپایدار» Media3 API همان سطح پایداری را دارند که کل سطح ExoPlayer v2 API دارد، و تضمینهای سطح Media3 API پایدار اصلاً در ExoPlayer v2 دردسترس نیست. تفاوت بهسادگی این است که خطای lint اکنون شما را از سطوح مختلف پایداری مطلع میکند.
رسیدگی به خطاهای lint میانای برنامهسازی کاربردی ناپایدار
برای جزئیات بیشتر درباره نحوه حاشیهنویسی کاربردهای Java و Kotlin از میاناهای برنامهسازی کاربردی ناپایدار با @OptIn، به بخش عیبیابی مربوط به این خطاهای lint مراجعه کنید.
میاناهای برنامهسازی کاربردی منسوخشده
ممکن است متوجه شوید که فراخوانیهای میاناهای برنامهسازی کاربردی منسوخشده در Android Studio خطخوردهاند. توصیه میکنیم این فراخوانیها را با جایگزین مناسب عوض کنید. نشانگر را روی نماد نگه دارید تا JavaDoc را ببینید که میگوید بهجای آن از کدام API استفاده کنید.
نمونههای کد و برنامههای نمایشی
- برنامه نمایشی جلسه AndroidX Media3 (تلفن همراه و WearOS)
- کنشهای سفارشی
- اعلان واسط کاربر سیستم، MediaButton/BT
- کنترل بازپخش «دستیار Google»
- UAMP: Android Media Player (branch media3) (mobile, AutomotiveOS)
- اعلان واسط کاربری سیستم، MediaButton/BT، ازسرگیری بازپخش
- کنترل بازپخش «دستیار Google»/ WearOS
- AutomotiveOS: فرمان سفارشی و ورود به سیستم