Uygulama ön planda değilken medya oynatmak genellikle tercih edilir. Örneğin, müzik çalarlar genellikle kullanıcı cihazını kilitlediğinde veya başka bir uygulama kullanırken müzik çalmaya devam eder. Media3 kitaplığı, arka planda oynatmayı desteklemenize olanak tanıyan bir dizi arayüz sunar.
MediaSessionService kullanma
Arka planda oynatmayı etkinleştirmek için Player ve MediaSession öğelerini ayrı bir Service içinde barındırmanız gerekir.
Bu sayede cihaz, uygulamanız ön planda olmasa bile medya sunmaya devam edebilir.
MediaSessionService, medya oturumunun uygulamanın etkinliğinden ayrı olarak çalışmasına olanak tanırBir hizmette oynatıcı barındırırken MediaSessionService kullanmanız gerekir.
Bunun için MediaSessionService sınıfını genişleten bir sınıf oluşturun ve medya oturumunuzu bu sınıfın içinde oluşturun.
MediaSessionService kullanıldığında Google Asistan, sistem medya kontrolleri, çevre birimlerindeki medya düğmeleri veya Wear OS gibi yardımcı cihazlar gibi harici istemciler, uygulamanızın kullanıcı arayüzü etkinliğine erişmeden hizmetinizi keşfedebilir, hizmetinize bağlanabilir ve oynatmayı kontrol edebilir. Hatta aynı anda aynı MediaSessionService hizmetine bağlı birden fazla istemci uygulaması olabilir ve her uygulamanın kendi MediaController hizmeti bulunur.
Hizmet yaşam döngüsünü uygulama
Hizmetinizin iki yaşam döngüsü yöntemini uygulamanız gerekir:
- İlk kumanda bağlanmak üzereyken ve hizmet örneklendirilip başlatıldığında
onCreate()çağrılır.PlayerveMediaSessionoluşturmak için en iyi yerdir. onDestroy(), hizmet durdurulurken çağrılır. Oynatıcı ve oturum dahil tüm kaynakların serbest bırakılması gerekir.
Kullanıcı uygulamayı son görevlerden kapattığında ne olacağını özelleştirmek için isteğe bağlı olarak onTaskRemoved(Intent) yöntemini geçersiz kılabilirsiniz. Varsayılan olarak, oynatma devam ediyorsa hizmet çalışır durumda bırakılır, aksi takdirde durdurulur.
Kotlin
class PlaybackService : MediaSessionService() { private var mediaSession: MediaSession? = null // Create your Player and MediaSession 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() } override fun onGetSession(controllerInfo: MediaSession.ControllerInfo): MediaSession? = mediaSession }
Java
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 public MediaSession onGetSession(MediaSession.ControllerInfo controllerInfo) { return mediaSession; } }
Oynatmayı arka planda devam ettirmek yerine, kullanıcı uygulamayı kapattığında hizmeti durdurabilirsiniz:
Kotlin
@OptIn(UnstableApi::class) override fun onTaskRemoved(rootIntent: Intent?) { pauseAllPlayersAndStopSelf() }
Java
@OptIn(markerClass = UnstableApi.class) @Override public void onTaskRemoved(@Nullable Intent rootIntent) { pauseAllPlayersAndStopSelf(); }
onTaskRemoved için diğer manuel uygulamalarda, oynatmanın devam edip etmediğini ve ön plan hizmetinin başlatılıp başlatılmadığını kontrol etmek için isPlaybackOngoing() kullanabilirsiniz.
Medya oturumuna erişim izni verme
Hizmet oluşturulduğunda oluşturulan medya oturumunuza diğer istemcilerin erişebilmesi için onGetSession() yöntemini geçersiz kılın.
Kotlin
class PlaybackService : MediaSessionService() { // [...] lifecycle methods omitted override fun onGetSession(controllerInfo: MediaSession.ControllerInfo): MediaSession? = mediaSession }
Java
class PlaybackService extends MediaSessionService { // [...] lifecycle methods omitted @Override public MediaSession onGetSession(MediaSession.ControllerInfo controllerInfo) { return mediaSession; } }
Hizmeti manifest dosyasında tanımlama
Bir uygulamanın, oynatma ön plan hizmetini çalıştırmak için FOREGROUND_SERVICE ve FOREGROUND_SERVICE_MEDIA_PLAYBACK izinlerine ihtiyacı vardır:
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" />
Ayrıca, manifest dosyasında Service sınıfınızı MediaSessionService intent filtresi ve mediaPlayback içeren bir foregroundServiceType ile beyan etmeniz gerekir.
<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 kullanarak oynatmayı kontrol etme
Oynatıcı kullanıcı arayüzünüzü içeren etkinlik veya parçada, MediaController kullanarak kullanıcı arayüzü ile medya oturumunuz arasında bağlantı oluşturabilirsiniz. Kullanıcı arayüzünüz, oturum içindeki oynatıcıya komut göndermek için medya kumandasını kullanır. MediaController oluşturma ve kullanma hakkında ayrıntılı bilgi için MediaController oluşturma kılavuzuna bakın.
MediaController komutlarını işleme
MediaSession, kumandadan gelen komutları MediaSession.Callback üzerinden alır. MediaSession başlatıldığında, MediaController tarafından oynatıcınıza gönderilen tüm komutları otomatik olarak işleyen varsayılan bir MediaSession.Callback uygulaması oluşturulur.
Bildirim
MediaSessionService, çoğu durumda işe yarayacak bir MediaNotification'yi sizin için otomatik olarak oluşturur. Varsayılan olarak, yayınlanan bildirim, medya oturumunuzdaki en son bilgilerle güncel kalan ve oynatma kontrollerini gösteren bir MediaStyle bildirimdir. MediaNotification, oturumunuzu bilir ve aynı oturuma bağlı diğer uygulamalarda oynatmayı kontrol etmek için kullanılabilir.
Örneğin, MediaSessionService kullanan bir müzik yayını uygulaması, MediaSession yapılandırmanıza göre oynatma kontrolleriyle birlikte oynatılan mevcut medya öğesinin başlığını, sanatçısını ve albüm kapağını gösteren bir MediaNotification oluşturur.
Gerekli meta veriler, medyada sağlanabilir veya aşağıdaki snippet'te olduğu gibi medya öğesinin bir parçası olarak beyan edilebilir:
Kotlin
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()
Java
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();
Bildirim yaşam döngüsü
Bildirim, Player oynatma listesinde MediaItem örnek olduğunda oluşturulur.
Tüm bildirim güncellemeleri, Player ve MediaSession durumuna göre otomatik olarak gerçekleşir.
Ön plan hizmeti çalışırken bildirim kaldırılamaz. Bildirimi hemen kaldırmak için Player.release() yöntemini çağırmanız veya Player.clearMediaItems() yöntemini kullanarak oynatma listesini temizlemeniz gerekir.
Oynatıcı 10 dakikadan uzun süre duraklatılır, durdurulur veya başarısız olursa ve kullanıcı başka bir etkileşimde bulunmazsa hizmet otomatik olarak ön plan hizmeti durumundan çıkarılır ve sistem tarafından yok edilebilir. Kullanıcının hizmet yaşam döngüsünü yeniden başlatmasına ve daha sonra oynatmayı devam ettirmesine olanak tanımak için oynatmayı devam ettirme özelliğini uygulayabilirsiniz.
Bildirim özelleştirme
Oynatılmakta olan öğeyle ilgili meta veriler, MediaItem.MediaMetadata değiştirilerek özelleştirilebilir. Mevcut bir öğenin meta verilerini güncellemek istiyorsanız oynatmayı kesintiye uğratmadan meta verileri güncellemek için Player.replaceMediaItem kullanabilirsiniz.
Android medya kontrolleri için özel medya düğmesi tercihleri ayarlayarak bildirimde gösterilen düğmelerden bazılarını da özelleştirebilirsiniz. Android medya kontrollerini özelleştirme hakkında daha fazla bilgi edinin.
Bildirimi daha fazla özelleştirmek için DefaultMediaNotificationProvider.Builder ile veya sağlayıcı arayüzünün özel bir uygulamasını oluşturarak MediaNotification.Provider oluşturun. setMediaNotificationProvider ile sağlayıcınızı MediaSessionService cihazınıza ekleyin.
Kaldığı yerden oynatma
MediaSessionService sonlandırıldıktan ve hatta cihaz yeniden başlatıldıktan sonra, kullanıcıların hizmeti yeniden başlatıp oynatmaya kaldıkları yerden devam etmelerini sağlamak için oynatmaya devam etme özelliği sunulabilir. Oynatmaya devam etme özelliği varsayılan olarak devre dışıdır. Bu, hizmetiniz çalışmıyorken kullanıcının oynatmaya devam edemeyeceği anlamına gelir. Bu özelliği etkinleştirmek için bir medya düğmesi alıcısı tanımlamanız ve onPlaybackResumption yöntemini uygulamanız gerekir.
Media3 medya düğmesi alıcısını bildirme
Manifest dosyanızda MediaButtonReceiver öğesini tanımlayarak başlayın:
<receiver android:name="androidx.media3.session.MediaButtonReceiver"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MEDIA_BUTTON" />
</intent-filter>
</receiver>
Kaldığı yerden oynatma geri çağırma işlevini uygulama
Bir Bluetooth cihazı veya Android sistem kullanıcı arayüzü devam ettirme özelliği tarafından oynatmanın devam ettirilmesi istendiğinde onPlaybackResumption() geri çağırma yöntemi çağrılır.
Kotlin
override fun onPlaybackResumption( mediaSession: MediaSession, controller: MediaSession.ControllerInfo, isForPlayback: Boolean, ): ListenableFuture<MediaSession.MediaItemsWithStartPosition> { val settableFuture = SettableFuture.create<MediaSession.MediaItemsWithStartPosition>() settableFuture.addListener( { // Your app is responsible for storing the playlist, metadata (like title // and artwork) of the current item and the start position to use here. val resumptionPlaylist = restorePlaylist() settableFuture.set(resumptionPlaylist) }, MoreExecutors.directExecutor(), ) return settableFuture }
Java
@Override public ListenableFuture<MediaItemsWithStartPosition> onPlaybackResumption( MediaSession mediaSession, ControllerInfo controller, boolean isForPlayback) { SettableFuture<MediaItemsWithStartPosition> settableFuture = SettableFuture.create(); settableFuture.addListener( () -> { // Your app is responsible for storing the playlist, metadata (like title // and artwork) of the current item and the start position to use here. MediaItemsWithStartPosition resumptionPlaylist = restorePlaylist(); settableFuture.set(resumptionPlaylist); }, MoreExecutors.directExecutor()); return settableFuture; }
Oynatma hızı, tekrar modu veya karışık modu gibi başka parametreler depoladıysanız onPlaybackResumption(), Media3 oynatıcıyı hazırlamadan ve geri çağırma tamamlandığında oynatmayı başlatmadan önce oynatıcıyı bu parametrelerle yapılandırmak için iyi bir yerdir.
Bu yöntem, isForPlayback değeri false olarak ayarlanmış cihaz yeniden başlatıldıktan sonra Android Sistem Arayüzü devam ettirme bildirimini oluşturmak için başlatma sırasında çağrılır. Zengin bildirimler için geçerli öğenin MediaMetadata gibi alanlarını title ve artworkData veya artworkUri ile doldurmanız önerilir. Ağ erişimi henüz kullanılamıyor olabileceğinden yerel olarak kullanılabilen değerler tercih edilmelidir. Oynatmanın devam ettirileceği konumu belirtmek için MediaMetadata.extras öğesine MediaConstants.EXTRAS_KEY_COMPLETION_STATUS ve MediaConstants.EXTRAS_KEY_COMPLETION_PERCENTAGE da ekleyebilirsiniz.
Gelişmiş kumanda yapılandırması ve geriye dönük uyumluluk
Yaygın senaryolardan biri, oynatmayı kontrol etmek ve oynatma listesini görüntülemek için uygulama kullanıcı arayüzünde MediaController kullanmaktır. Aynı zamanda oturum, Android medya kontrolleri ve mobil cihazlarda veya TV'de Asistan, saatler için Wear OS ve arabalarda Android Auto gibi harici istemcilere de sunulur. Media3 oturum demo uygulaması, bu tür bir senaryoyu uygulayan bir uygulama örneğidir.
Bu harici istemciler, eski AndroidX kitaplığının MediaControllerCompat veya Android platformunun android.media.session.MediaController gibi API'lerini kullanabilir. Media3, eski kitaplıkla tamamen geriye dönük uyumludur ve Android platformu API'si ile birlikte çalışabilirlik sağlar.
Güvenilir denetleyicileri belirleme
Herhangi bir uygulama, medya oturumunuza veya kitaplığınıza bağlanmayı deneyebilir. Sistem denetleyicilerine, medya içeriği kontrolü iznine sahip denetleyicilere ve kendi uygulamanıza erişimi kısıtlamak istiyorsanız temel erişim kontrolü için ControllerInfo.isTrusted() kullanabilirsiniz. Alternatif olarak, aşağıdaki bölümlerde açıklandığı gibi medya bildirimi denetleyicisi veya Android Auto denetleyicileri gibi daha spesifik denetleyiciler tanımlayabilirsiniz.
Medya bildirimi denetleyicisini kullanma
Bu eski ve platform denetleyicilerinin aynı durumu paylaştığını ve görünürlüğün denetleyiciye göre özelleştirilemeyeceğini (ör. mevcut PlaybackState.getActions() ve PlaybackState.getCustomActions()) anlamak önemlidir.
Bu eski ve platform denetleyicileriyle uyumluluk için platform medya oturumunda ayarlanan durumu yapılandırmak üzere medya bildirimi denetleyicisini kullanabilirsiniz.
Örneğin, bir uygulama, kullanılabilir komutları ve medya düğmesi tercihlerini platform oturumuna özel olarak ayarlamak için MediaSession.Callback.onConnect() uygulamasını aşağıdaki gibi sağlayabilir:
Kotlin
override fun onConnectAsync( session: MediaSession, controller: MediaSession.ControllerInfo, ): ListenableFuture<ConnectionResult> { if (session.isMediaNotificationController(controller)) { 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 immediateFuture( AcceptedResultBuilder(session, controller) .setMediaButtonPreferences(listOf(seekBackButton, seekForwardButton)) .setAvailablePlayerCommands(playerCommands) .build() ) } // Default commands with default button preferences for all other controllers. return immediateFuture(AcceptedResultBuilder(session, controller).build()) }
Java
@Override public ListenableFuture<ConnectionResult> onConnectAsync( MediaSession session, MediaSession.ControllerInfo controller) { if (session.isMediaNotificationController(controller)) { 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 immediateFuture( new AcceptedResultBuilder(session, controller) .setMediaButtonPreferences(ImmutableList.of(seekBackButton, seekForwardButton)) .setAvailablePlayerCommands(playerCommands) .build()); } // Default commands with default button preferences for all other controllers. return immediateFuture(new AcceptedResultBuilder(session, controller).build()); }
Android Auto'ya özel komutlar gönderme yetkisi verme
MediaLibraryService kullanırken
ve mobil uygulamayla Android Auto'yu desteklemek için Android Auto denetleyicisi, uygun komutların kullanılabilir olmasını gerektirir. Aksi takdirde Media3, bu denetleyiciden gelen
özel komutları reddeder:
Kotlin
override fun onConnectAsync( session: MediaSession, controller: MediaSession.ControllerInfo, ): ListenableFuture<ConnectionResult> { val sessionCommands = ConnectionResult.DEFAULT_SESSION_COMMANDS.buildUpon().add(customCommand).build() if (session.isMediaNotificationController(controller)) { // ... See above. } else if (session.isAutoCompanionController(controller)) { // Available commands to accept incoming custom commands from Auto. return immediateFuture( AcceptedResultBuilder(session, controller) .setAvailableSessionCommands(sessionCommands) .build() ) } // Default commands for all other controllers. return immediateFuture(AcceptedResultBuilder(session, controller).build()) }
Java
@Override public ListenableFuture<ConnectionResult> onConnectAsync( MediaSession session, MediaSession.ControllerInfo controller) { SessionCommands sessionCommands = ConnectionResult.DEFAULT_SESSION_COMMANDS.buildUpon().add(customCommand).build(); if (session.isMediaNotificationController(controller)) { // ... See above. } else if (session.isAutoCompanionController(controller)) { // Available commands to accept incoming custom commands from Auto. return immediateFuture( new AcceptedResultBuilder(session, controller) .setAvailableSessionCommands(sessionCommands) .build()); } // Default commands for all other controllers. return immediateFuture(new AcceptedResultBuilder(session, controller).build()); }
Oturum demo uygulamasında, Automotive OS desteğini gösteren ve ayrı bir APK gerektiren bir otomotiv modülü bulunur.