معمولاً پخش رسانه در حالی که یک برنامه در پیش زمینه نیست، مطلوب است. به عنوان مثال، پخش کننده موسیقی معمولاً زمانی که کاربر دستگاه خود را قفل کرده است یا از برنامه دیگری استفاده می کند، به پخش موسیقی ادامه می دهد. کتابخانه Media3 مجموعه ای از رابط ها را ارائه می دهد که به شما امکان می دهد از پخش پس زمینه پشتیبانی کنید.
از MediaSessionService استفاده کنید
برای فعال کردن پخش پسزمینه، باید Player
و MediaSession
در یک سرویس جداگانه قرار دهید. این به دستگاه امکان می دهد حتی زمانی که برنامه شما در پیش زمینه نیست، به پخش رسانه ادامه دهد.

MediaSessionService
به جلسه رسانه اجازه می دهد جدا از فعالیت برنامه اجرا شود. هنگام میزبانی یک پخش کننده در داخل یک سرویس، باید از MediaSessionService
استفاده کنید. برای انجام این کار، یک کلاس ایجاد کنید که MediaSessionService
را گسترش دهد و جلسه رسانه خود را در داخل آن ایجاد کنید.
استفاده از MediaSessionService
این امکان را برای کلاینتهای خارجی مانند Google Assistant، کنترلهای رسانه سیستم، دکمههای رسانه در دستگاههای جانبی یا دستگاههای همراه مانند Wear OS فراهم میکند تا سرویس شما را کشف کنند، به آن متصل شوند و پخش را کنترل کنند، همگی بدون دسترسی به فعالیت رابط کاربری برنامه شما. در واقع، میتوان چندین برنامه کلاینت را به طور همزمان به یک MediaSessionService
متصل کرد که هر برنامه MediaController
مخصوص به خود را دارد.
چرخه عمر سرویس را پیاده سازی کنید
شما باید دو روش چرخه عمر سرویس خود را پیاده سازی کنید:
-
onCreate()
زمانی فراخوانی می شود که اولین کنترلر در شرف اتصال است و سرویس نمونه سازی و راه اندازی می شود. این بهترین مکان برای ساختPlayer
وMediaSession
است. -
onDestroy()
زمانی فراخوانی می شود که سرویس در حال توقف است. همه منابع از جمله پخش کننده و جلسه باید آزاد شوند.
میتوانید بهصورت اختیاری، onTaskRemoved(Intent)
لغو کنید تا زمانی که کاربر برنامه را از وظایف اخیر رد میکند، چه اتفاقی میافتد. بهطور پیشفرض، اگر پخش ادامه داشته باشد، سرویس اجرا میشود و در غیر این صورت متوقف میشود.
کاتلین
class PlaybackService : MediaSessionService() { private var mediaSession: MediaSession? = null // Create your player and media session in the onCreate lifecycle event override fun onCreate() { super.onCreate() val player = ExoPlayer.Builder(this).build() mediaSession = MediaSession.Builder(this, player).build() } // Remember to release the player and media session in onDestroy override fun onDestroy() { mediaSession?.run { player.release() release() mediaSession = null } super.onDestroy() } }
جاوا
public class PlaybackService extends MediaSessionService { private MediaSession mediaSession = null; // Create your Player and MediaSession in the onCreate lifecycle event @Override public void onCreate() { super.onCreate(); ExoPlayer player = new ExoPlayer.Builder(this).build(); mediaSession = new MediaSession.Builder(this, player).build(); } // Remember to release the player and media session in onDestroy @Override public void onDestroy() { mediaSession.getPlayer().release(); mediaSession.release(); mediaSession = null; super.onDestroy(); } }
به عنوان جایگزینی برای ادامه پخش در پسزمینه، میتوانید در هر صورت زمانی که کاربر برنامه را رد کرد، سرویس را متوقف کنید:
کاتلین
override fun onTaskRemoved(rootIntent: Intent?) { pauseAllPlayersAndStopSelf() }
جاوا
@Override public void onTaskRemoved(@Nullable Intent rootIntent) { pauseAllPlayersAndStopSelf(); }
برای هر پیادهسازی دستی دیگری از onTaskRemoved
، میتوانید از isPlaybackOngoing()
استفاده کنید تا بررسی کنید که آیا پخش در حال انجام است و سرویس پیشزمینه شروع شده است یا خیر.
امکان دسترسی به جلسه رسانه را فراهم کنید
روش onGetSession()
را نادیده بگیرید تا به سایر کلاینتها به جلسه رسانه شما که در زمان ایجاد سرویس ساخته شده است دسترسی داشته باشند.
کاتلین
class PlaybackService : MediaSessionService() { private var mediaSession: MediaSession? = null // [...] lifecycle methods omitted override fun onGetSession(controllerInfo: MediaSession.ControllerInfo): MediaSession? = mediaSession }
جاوا
public class PlaybackService extends MediaSessionService { private MediaSession mediaSession = null; // [...] lifecycle methods omitted @Override public MediaSession onGetSession(MediaSession.ControllerInfo controllerInfo) { return mediaSession; } }
سرویس را در مانیفست اعلام کنید
یک برنامه برای اجرای یک سرویس پیشزمینه پخش به مجوزهای FOREGROUND_SERVICE
و FOREGROUND_SERVICE_MEDIA_PLAYBACK
نیاز دارد:
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" />
همچنین باید کلاس Service
خود را در مانیفست با فیلتر قصد MediaSessionService
و foregroundServiceType
که شامل mediaPlayback
است، اعلام کنید.
<service
android:name=".PlaybackService"
android:foregroundServiceType="mediaPlayback"
android:exported="true">
<intent-filter>
<action android:name="androidx.media3.session.MediaSessionService"/>
<action android:name="android.media.browse.MediaBrowserService"/>
</intent-filter>
</service>
پخش را با استفاده از MediaController
کنترل کنید
در Activity یا Fragment حاوی رابط کاربری پخش کننده شما، می توانید با استفاده از MediaController
یک پیوند بین رابط کاربری و جلسه رسانه خود ایجاد کنید. رابط کاربری شما از کنترلر رسانه برای ارسال دستورات از رابط کاربری شما به پخش کننده در جلسه استفاده می کند. برای جزئیات بیشتر در مورد ایجاد و استفاده از MediaController
به راهنمای MediaController
یک MediaController مراجعه کنید.
کنترل دستورات MediaController
MediaSession
دستورات را از طریق MediaSession.Callback
خود از کنترلر دریافت می کند. راهاندازی یک MediaSession
یک پیادهسازی پیشفرض از MediaSession.Callback
ایجاد میکند که بهطور خودکار تمام دستوراتی را که MediaController
به پخشکننده شما ارسال میکند کنترل میکند.
اطلاع رسانی
یک MediaSessionService
به طور خودکار یک MediaNotification
برای شما ایجاد می کند که در بیشتر موارد باید کار کند. به طور پیش فرض، اعلان منتشر شده یک اعلان MediaStyle
است که با آخرین اطلاعات جلسه رسانه شما به روز می شود و کنترل های پخش را نمایش می دهد. MediaNotification
از جلسه شما آگاه است و می تواند برای کنترل پخش هر برنامه دیگری که به همان جلسه متصل است استفاده شود.
به عنوان مثال، یک برنامه پخش موسیقی با استفاده از MediaSessionService
یک MediaNotification
ایجاد می کند که عنوان، هنرمند و هنر آلبوم را برای آیتم رسانه فعلی در حال پخش در کنار کنترل های پخش بر اساس پیکربندی MediaSession
شما نمایش می دهد.
فراداده مورد نیاز را می توان در رسانه ارائه کرد یا به عنوان بخشی از آیتم رسانه ای در قطعه زیر اعلام کرد:
کاتلین
val mediaItem = MediaItem.Builder() .setMediaId("media-1") .setUri(mediaUri) .setMediaMetadata( MediaMetadata.Builder() .setArtist("David Bowie") .setTitle("Heroes") .setArtworkUri(artworkUri) .build() ) .build() mediaController.setMediaItem(mediaItem) mediaController.prepare() mediaController.play()
جاوا
MediaItem mediaItem = new MediaItem.Builder() .setMediaId("media-1") .setUri(mediaUri) .setMediaMetadata( new MediaMetadata.Builder() .setArtist("David Bowie") .setTitle("Heroes") .setArtworkUri(artworkUri) .build()) .build(); mediaController.setMediaItem(mediaItem); mediaController.prepare(); mediaController.play();
چرخه عمر اعلان
به محض اینکه Player
موارد MediaItem
را در لیست پخش خود داشته باشد، اعلان ایجاد می شود.
همه بهروزرسانیهای اعلانها بهطور خودکار براساس وضعیت Player
و MediaSession
انجام میشوند.
هنگامی که سرویس پیش زمینه در حال اجرا است، اعلان حذف نمی شود. برای حذف فوری اعلان، باید با Player.release()
تماس بگیرید یا لیست پخش را با استفاده از Player.clearMediaItems()
پاک کنید.
اگر پخش کننده برای بیش از 10 دقیقه بدون تعامل بیشتر با کاربر متوقف شود، متوقف شود یا از کار بیفتد، سرویس به طور خودکار از وضعیت سرویس پیش زمینه خارج می شود تا توسط سیستم از بین برود. شما می توانید از سرگیری پخش را پیاده سازی کنید تا به کاربر اجازه دهید چرخه عمر سرویس را مجدداً راه اندازی کند و در زمان بعدی پخش را از سر بگیرد.
سفارشی سازی اعلان
فراداده مورد در حال پخش را می توان با تغییر MediaItem.MediaMetadata
سفارشی کرد. اگر میخواهید فراداده یک مورد موجود را بهروزرسانی کنید، میتوانید از Player.replaceMediaItem
برای بهروزرسانی فراداده بدون وقفه در پخش استفاده کنید.
همچنین میتوانید برخی از دکمههای نشاندادهشده در اعلان را با تنظیم تنظیمات برگزیده دکمه رسانه سفارشی برای کنترلهای Android Media شخصیسازی کنید. درباره سفارشی کردن کنترلهای Android Media بیشتر بخوانید .
برای سفارشی کردن بیشتر خود اعلان، یک MediaNotification.Provider
با DefaultMediaNotificationProvider.Builder
یا با ایجاد یک پیاده سازی سفارشی از رابط ارائه دهنده ایجاد کنید. ارائه دهنده خود را با setMediaNotificationProvider
به MediaSessionService
خود اضافه کنید.
از سرگیری پخش
پس از پایان یافتن MediaSessionService
و حتی پس از راهاندازی مجدد دستگاه، امکان ازسرگیری پخش وجود دارد تا به کاربران اجازه دهد سرویس را مجدداً راهاندازی کنند و پخش را از جایی که متوقف کردهاند از سر بگیرند. به طور پیش فرض، از سرگیری پخش خاموش است. این بدان معنی است که کاربر نمی تواند پخش را در زمانی که سرویس شما اجرا نمی کند، از سر بگیرد. برای شرکت در این ویژگی، باید یک گیرنده دکمه رسانه را اعلام کنید و روش onPlaybackResumption
را پیاده سازی کنید.
گیرنده دکمه رسانه Media3 را اعلام کنید
با اعلام MediaButtonReceiver
در مانیفست خود شروع کنید:
<receiver android:name="androidx.media3.session.MediaButtonReceiver"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MEDIA_BUTTON" />
</intent-filter>
</receiver>
اجرای مجدد تماس مجدد پخش
هنگامی که از سرگیری پخش توسط یک دستگاه بلوتوث یا ویژگی از سرگیری رابط کاربری سیستم اندروید درخواست می شود، روش پاسخ به تماس onPlaybackResumption()
فراخوانی می شود.
کاتلین
override fun onPlaybackResumption( mediaSession: MediaSession, controller: ControllerInfo ): ListenableFuture<MediaItemsWithStartPosition> { val settable = SettableFuture.create<MediaItemsWithStartPosition>() scope.launch { // Your app is responsible for storing the playlist and the start position // to use here val resumptionPlaylist = restorePlaylist() settable.set(resumptionPlaylist) } return settable }
جاوا
@Override public ListenableFuture<MediaItemsWithStartPosition> onPlaybackResumption( MediaSession mediaSession, ControllerInfo controller ) { SettableFuture<MediaItemsWithStartPosition> settableFuture = SettableFuture.create(); settableFuture.addListener(() -> { // Your app is responsible for storing the playlist and the start position // to use here MediaItemsWithStartPosition resumptionPlaylist = restorePlaylist(); settableFuture.set(resumptionPlaylist); }, MoreExecutors.directExecutor()); return settableFuture; }
اگر پارامترهای دیگری مانند سرعت پخش، حالت تکرار یا حالت shuffle را ذخیره کردهاید، onPlaybackResumption()
مکان خوبی برای پیکربندی پخشکننده با این پارامترها قبل از اینکه Media3 پخشکننده را آماده کند و پس از اتمام تماس مجدد شروع به پخش کند، است.
پیکربندی کنترلر پیشرفته و سازگاری با عقب
یک سناریوی رایج استفاده از MediaController
در رابط کاربری برنامه برای کنترل پخش و نمایش لیست پخش است. در همان زمان، این جلسه در معرض مشتریان خارجی مانند کنترلهای رسانه Android و Assistant در تلفن همراه یا تلویزیون، Wear OS برای ساعتها و Android Auto در اتومبیلها قرار میگیرد. برنامه نمایشی جلسه Media3 نمونه ای از برنامه هایی است که چنین سناریویی را پیاده سازی می کند.
این مشتریان خارجی ممکن است از APIهایی مانند MediaControllerCompat
کتابخانه قدیمی AndroidX یا android.media.session.MediaController
پلت فرم Android استفاده کنند. Media3 کاملاً با کتابخانه قدیمی سازگار است و قابلیت همکاری با API پلتفرم Android را فراهم می کند.
از کنترلر اعلان رسانه استفاده کنید
درک این نکته مهم است که این کنترلکنندههای قدیمی و پلتفرم حالت یکسانی دارند و قابلیت مشاهده توسط کنترلر قابل تنظیم نیست (برای مثال PlaybackState.getActions()
و PlaybackState.getCustomActions()
موجود). می توانید از کنترلر اعلان رسانه برای پیکربندی وضعیت تنظیم شده در جلسه رسانه پلت فرم برای سازگاری با این کنترلرهای قدیمی و پلت فرم استفاده کنید.
به عنوان مثال، یک برنامه میتواند اجرای MediaSession.Callback.onConnect()
را برای تنظیم دستورات موجود و تنظیمات برگزیده دکمه رسانه بهطور خاص برای جلسه پلتفرم به شرح زیر ارائه دهد:
کاتلین
override fun onConnect( session: MediaSession, controller: MediaSession.ControllerInfo ): ConnectionResult { if (session.isMediaNotificationController(controller)) { val sessionCommands = ConnectionResult.DEFAULT_SESSION_COMMANDS.buildUpon() .add(customCommandSeekBackward) .add(customCommandSeekForward) .build() val playerCommands = ConnectionResult.DEFAULT_PLAYER_COMMANDS.buildUpon() .remove(COMMAND_SEEK_TO_PREVIOUS) .remove(COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM) .remove(COMMAND_SEEK_TO_NEXT) .remove(COMMAND_SEEK_TO_NEXT_MEDIA_ITEM) .build() // Custom button preferences and commands to configure the platform session. return AcceptedResultBuilder(session) .setMediaButtonPreferences( ImmutableList.of( createSeekBackwardButton(customCommandSeekBackward), createSeekForwardButton(customCommandSeekForward)) ) .setAvailablePlayerCommands(playerCommands) .setAvailableSessionCommands(sessionCommands) .build() } // Default commands with default button preferences for all other controllers. return AcceptedResultBuilder(session).build() }
جاوا
@Override public ConnectionResult onConnect( MediaSession session, MediaSession.ControllerInfo controller) { if (session.isMediaNotificationController(controller)) { SessionCommands sessionCommands = ConnectionResult.DEFAULT_SESSION_COMMANDS .buildUpon() .add(customCommandSeekBackward) .add(customCommandSeekForward) .build(); Player.Commands playerCommands = ConnectionResult.DEFAULT_PLAYER_COMMANDS .buildUpon() .remove(COMMAND_SEEK_TO_PREVIOUS) .remove(COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM) .remove(COMMAND_SEEK_TO_NEXT) .remove(COMMAND_SEEK_TO_NEXT_MEDIA_ITEM) .build(); // Custom button preferences and commands to configure the platform session. return new AcceptedResultBuilder(session) .setMediaButtonPreferences( ImmutableList.of( createSeekBackwardButton(customCommandSeekBackward), createSeekForwardButton(customCommandSeekForward))) .setAvailablePlayerCommands(playerCommands) .setAvailableSessionCommands(sessionCommands) .build(); } // Default commands with default button preferences for all other controllers. return new AcceptedResultBuilder(session).build(); }
مجوز Android Auto برای ارسال دستورات سفارشی
هنگام استفاده از MediaLibraryService
و برای پشتیبانی از Android Auto با برنامه تلفن همراه، کنترلکننده Android Auto به دستورات موجود نیاز دارد، در غیر این صورت Media3 دستورات سفارشی دریافتی از آن کنترلکننده را رد میکند:
کاتلین
override fun onConnect( session: MediaSession, controller: MediaSession.ControllerInfo ): ConnectionResult { val sessionCommands = ConnectionResult.DEFAULT_SESSION_AND_LIBRARY_COMMANDS.buildUpon() .add(customCommandSeekBackward) .add(customCommandSeekForward) .build() if (session.isMediaNotificationController(controller)) { // [...] See above. } else if (session.isAutoCompanionController(controller)) { // Available session commands to accept incoming custom commands from Auto. return AcceptedResultBuilder(session) .setAvailableSessionCommands(sessionCommands) .build() } // Default commands for all other controllers. return AcceptedResultBuilder(session).build() }
جاوا
@Override public ConnectionResult onConnect( MediaSession session, MediaSession.ControllerInfo controller) { SessionCommands sessionCommands = ConnectionResult.DEFAULT_SESSION_COMMANDS .buildUpon() .add(customCommandSeekBackward) .add(customCommandSeekForward) .build(); if (session.isMediaNotificationController(controller)) { // [...] See above. } else if (session.isAutoCompanionController(controller)) { // Available commands to accept incoming custom commands from Auto. return new AcceptedResultBuilder(session) .setAvailableSessionCommands(sessionCommands) .build(); } // Default commands for all other controllers. return new AcceptedResultBuilder(session).build(); }
برنامه نمایشی جلسه دارای یک ماژول خودرو است که پشتیبانی از سیستم عامل Automotive را نشان می دهد که به یک APK جداگانه نیاز دارد.