Uygulamanız, manifest dosyasında intent filtresiyle MediaBrowserService
öğesini beyan etmelidir. Kendi hizmet adınızı seçebilirsiniz; aşağıdaki örnekte "MediaPlaybackService" uzantısıdır.
<service android:name=".MediaPlaybackService">
<intent-filter>
<action android:name="android.media.browse.MediaBrowserService" />
</intent-filter>
</service>
Not: MediaBrowserService
işlevinin önerilen uygulaması
MediaBrowserServiceCompat
.
Bu,
medya uyumluluğu destek kitaplığı üzerinden değiştirebilirsiniz.
Bu sayfa genelinde "MediaTarayıcıHizmeti" terimi proje yöneticisinin
/ MediaBrowserServiceCompat
.
Medya oturumunu başlat
Hizmet, onCreate()
yaşam döngüsü geri çağırma yöntemini aldığında şu adımları uygulamalıdır:
- Medya oturumunu oluşturma ve başlatma
- Medya oturumu geri çağırmasını ayarla
- Medya oturumu jetonunu ayarlama
Aşağıdaki onCreate()
kodu, şu adımları gösterir:
Kotlin
private const val MY_MEDIA_ROOT_ID = "media_root_id" private const val MY_EMPTY_MEDIA_ROOT_ID = "empty_root_id" class MediaPlaybackService : MediaBrowserServiceCompat() { private var mediaSession: MediaSessionCompat? = null private lateinit var stateBuilder: PlaybackStateCompat.Builder override fun onCreate() { super.onCreate() // Create a MediaSessionCompat mediaSession = MediaSessionCompat(baseContext, LOG_TAG).apply { // Enable callbacks from MediaButtons and TransportControls setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS or MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS ) // Set an initial PlaybackState with ACTION_PLAY, so media buttons can start the player stateBuilder = PlaybackStateCompat.Builder() .setActions(PlaybackStateCompat.ACTION_PLAY or PlaybackStateCompat.ACTION_PLAY_PAUSE ) setPlaybackState(stateBuilder.build()) // MySessionCallback() has methods that handle callbacks from a media controller setCallback(MySessionCallback()) // Set the session's token so that client activities can communicate with it. setSessionToken(sessionToken) } } }
Java
public class MediaPlaybackService extends MediaBrowserServiceCompat { private static final String MY_MEDIA_ROOT_ID = "media_root_id"; private static final String MY_EMPTY_MEDIA_ROOT_ID = "empty_root_id"; private MediaSessionCompat mediaSession; private PlaybackStateCompat.Builder stateBuilder; @Override public void onCreate() { super.onCreate(); // Create a MediaSessionCompat mediaSession = new MediaSessionCompat(context, LOG_TAG); // Enable callbacks from MediaButtons and TransportControls mediaSession.setFlags( MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS | MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS); // Set an initial PlaybackState with ACTION_PLAY, so media buttons can start the player stateBuilder = new PlaybackStateCompat.Builder() .setActions( PlaybackStateCompat.ACTION_PLAY | PlaybackStateCompat.ACTION_PLAY_PAUSE); mediaSession.setPlaybackState(stateBuilder.build()); // MySessionCallback() has methods that handle callbacks from a media controller mediaSession.setCallback(new MySessionCallback()); // Set the session's token so that client activities can communicate with it. setSessionToken(mediaSession.getSessionToken()); } }
İstemci bağlantılarını yönetme
MediaBrowserService
, istemci bağlantılarını yönetmek için kullanılan iki yönteme sahiptir:
onGetRoot()
kontrolleri
ve erişimi olan kullanıcılar
onLoadChildren()
bir istemciye, MediaBrowserService
öğesinin içerik hiyerarşisinin bir menüsünü oluşturma ve görüntüleme olanağı sağlar.
onGetRoot()
ile istemci bağlantıları kontrol ediliyor
onGetRoot()
yöntemi, içerik hiyerarşisinin kök düğümünü döndürür. Öğe
yöntemi null değerini döndürürse bağlantı reddedilir.
Müşterilerin hizmetinize bağlanmasını ve hizmetin medya içeriğine göz atmasını sağlamak için onGetRoot(), boş olmayan bir BrowserRoot döndürmelidir. Bu, içerik hiyerarşinizi temsil eder.
İstemcilerin göz atmadan MediaSession hesabınıza bağlanmasına izin vermek için onGetRoot() onGetRoot() yine de boş olmayan bir BrowserRoot döndürmelidir, ancak kök kimliği bir olabilir.
Tipik bir onGetRoot()
uygulaması aşağıdaki gibi görünebilir:
Kotlin
override fun onGetRoot( clientPackageName: String, clientUid: Int, rootHints: Bundle? ): MediaBrowserServiceCompat.BrowserRoot { // (Optional) Control the level of access for the specified package name. // You'll need to write your own logic to do this. return if (allowBrowsing(clientPackageName, clientUid)) { // Returns a root ID that clients can use with onLoadChildren() to retrieve // the content hierarchy. MediaBrowserServiceCompat.BrowserRoot(MY_MEDIA_ROOT_ID, null) } else { // Clients can connect, but this BrowserRoot is an empty hierarchy // so onLoadChildren returns nothing. This disables the ability to browse for content. MediaBrowserServiceCompat.BrowserRoot(MY_EMPTY_MEDIA_ROOT_ID, null) } }
Java
@Override public BrowserRoot onGetRoot(String clientPackageName, int clientUid, Bundle rootHints) { // (Optional) Control the level of access for the specified package name. // You'll need to write your own logic to do this. if (allowBrowsing(clientPackageName, clientUid)) { // Returns a root ID that clients can use with onLoadChildren() to retrieve // the content hierarchy. return new BrowserRoot(MY_MEDIA_ROOT_ID, null); } else { // Clients can connect, but this BrowserRoot is an empty hierarchy // so onLoadChildren returns nothing. This disables the ability to browse for content. return new BrowserRoot(MY_EMPTY_MEDIA_ROOT_ID, null); } }
Bazı durumlarda, kiminle bağlantı kurabileceğini kontrol etmek
MediaBrowserService
cihazınıza. Bunun bir yolu, erişim kontrol listesi (EKL) kullanmaktır.
Bu ayar hangi bağlantılara izin verildiğini belirtir ya da alternatif olarak
hangi bağlantıların yasaklanacağını belirleyin. EKL uygulama örneği için
izin veren başka bir bağlantı kullanıyorsanız
Paket Doğrulayıcı
Universal Android Music Player'daki sınıf
örnek uygulama.
İçeriğe bağlı olarak, farklı içerik hiyerarşileri
ne tür bir istemcinin sorgu yaptığını gösterir. Özellikle de Android Auto,
Kullanıcıların ses uygulamalarıyla etkileşime geçmesi. Daha fazla bilgi için Şunlar için Ses Çalma:
Otomatik. Siz
İstemciyi belirlemek için bağlantı zamanında clientPackageName
öğesine bakabilir
türü ve istemciye (veya rootHints
) bağlı olarak farklı bir BrowserRoot
döndürür
.
onLoadChildren()
ile içerik paylaşılıyor
İstemci bağlandıktan sonra, kullanıcı arayüzünün yerel bir temsilini oluşturmak için MediaBrowserCompat.subscribe()
öğesine yinelenen çağrılar yaparak içerik hiyerarşisini dolaşabilir. subscribe()
yöntemi, onLoadChildren()
geri çağırmasını hizmete gönderir ve bu işlem, MediaBrowser.MediaItem
nesnelerinin bir listesini döndürür.
Her MediaItem, opak bir jeton olan benzersiz bir kimlik dizesine sahiptir. Müşteri bir alt menüyü açmak veya bir öğeyi oynatmak istediğinde kimliği iletir. Hizmetiniz, kimliği uygun menü düğümü veya içerik öğesiyle ilişkilendirmekten sorumludur.
Basit bir onLoadChildren()
uygulaması aşağıdaki gibi görünebilir:
Kotlin
override fun onLoadChildren( parentMediaId: String, result: MediaBrowserServiceCompat.Result<List<MediaBrowserCompat.MediaItem>> ) { // Browsing not allowed if (MY_EMPTY_MEDIA_ROOT_ID == parentMediaId) { result.sendResult(null) return } // Assume for example that the music catalog is already loaded/cached. val mediaItems = emptyList<MediaBrowserCompat.MediaItem>() // Check if this is the root menu: if (MY_MEDIA_ROOT_ID == parentMediaId) { // Build the MediaItem objects for the top level, // and put them in the mediaItems list... } else { // Examine the passed parentMediaId to see which submenu we're at, // and put the children of that menu in the mediaItems list... } result.sendResult(mediaItems) }
Java
@Override public void onLoadChildren(final String parentMediaId, final Result<List<MediaItem>> result) { // Browsing not allowed if (TextUtils.equals(MY_EMPTY_MEDIA_ROOT_ID, parentMediaId)) { result.sendResult(null); return; } // Assume for example that the music catalog is already loaded/cached. List<MediaItem> mediaItems = new ArrayList<>(); // Check if this is the root menu: if (MY_MEDIA_ROOT_ID.equals(parentMediaId)) { // Build the MediaItem objects for the top level, // and put them in the mediaItems list... } else { // Examine the passed parentMediaId to see which submenu we're at, // and put the children of that menu in the mediaItems list... } result.sendResult(mediaItems); }
Not: MediaTarayıcı Hizmeti tarafından yayınlanan MediaItem
nesne
simge bit eşlemleri içermemelidir. Telefon ederek bunun yerine bir Uri
kullanın
setIconUri()
her öğe için MediaDescription
oluşturduğunuzu varsayalım.
onLoadChildren()
öğesinin nasıl uygulanacağına ilişkin bir örnek için Evrensel Android Müzik Çalar örnek uygulamasına bakın.
Medya tarayıcısı hizmet yaşam döngüsü
Bir Android hizmetinin davranışı, hizmetin bir veya daha fazla istemciye başlatılmasına ya da bağlı olmasına bağlıdır. Bir hizmet oluşturulduktan sonra başlatılabilir, bağlanabilir veya her ikisi birden yapılabilir. Bu durumların hepsinde, tamamen işlevseldir ve yapmak üzere tasarlandığı işleri yapabilir. Aradaki fark, hizmetin ne kadar süre boyunca açık olacağıdır. Bağlı bir hizmet, tüm bağlı istemcilerinin bağlantısı kaldırılana kadar kaldırılmaz. Başlatılan bir hizmet, açıkça durdurulabilir ve yok edilebilir (artık herhangi bir istemciye bağlı olmadığı varsayılır).
Başka bir etkinlikte çalışan MediaBrowser
, MediaBrowserService
öğesine bağlandığında etkinliği hizmete bağlar ve hizmeti bağlı hale getirir (ancak başlatılmaz). Bu varsayılan davranış MediaBrowserServiceCompat
sınıfında yerleşiktir.
Bağlı olan (ve başlatılmamış) bir hizmet, tüm istemcilerinin bağlantısı kaldırıldığında yok edilir. Bu noktada kullanıcı arayüzü etkinliğiniz kesilirse hizmet kaldırılır. Henüz hiç müzik çalmadıysanız bu durum bir sorun teşkil etmez. Ancak oynatma başladığında kullanıcı muhtemelen uygulama değiştirseniz bile dinlemeye devam etmeyi bekler. Başka bir uygulamayla çalışmak için kullanıcı arayüzünün bağlantısını kaldırdığınızda oynatıcıyı kaldırmak istemezsiniz.
Bu nedenle, başlangıç sırasında hizmetin başlatıldığından emin olmanız gerekir
startService()
numaralı telefonu arayarak oynayın. CEVAP
başlatılan hizmetin bağlı olup olmadığından bağımsız olarak açıkça durdurulması gerekir. Bu
Kontrol eden kullanıcı arayüzü olsa bile oynatıcınızın çalışmaya devam etmesini sağlar.
ve etkinliğin bağlantısı kaldırılır.
Başlatılan bir hizmeti durdurmak için Context.stopService()
veya stopSelf()
numaralı telefonu arayın. Sistem, hizmeti mümkün olan en kısa sürede durdurur ve kaldırır. Ancak hizmete hâlâ bir veya daha fazla istemci bağlı durumdaysa hizmeti durdurma çağrısı, tüm istemcilerinin bağlantısı kaldırılana kadar ertelenir.
MediaBrowserService
öğesinin yaşam döngüsü; oluşturulma şekli, bağlı istemci sayısı ve medya oturumu geri çağırmalarından aldığı çağrılarla kontrol edilir. Özetlemek gerekirse:
- Hizmet, bir medya düğmesine yanıt olarak başlatıldığında veya bir etkinlik buna bağlandığında (
MediaBrowser
üzerinden bağlandıktan sonra) oluşturulur. - Medya oturumu
onPlay()
geri çağırması,startService()
çağrısı yapan kodu içermelidir. Bu işlem, hizmete bağlı tüm kullanıcı arayüzüMediaBrowser
etkinliklerinin bağlantısı kaldırıldığında bile hizmetin başlamasını ve çalışmaya devam etmesini sağlar. onStop()
geri çağırmasıstopSelf()
numarasını arayacaktır. Hizmet başlatılmışsa bu işlem durdurulur. Ayrıca, bağlı herhangi bir etkinlik yoksa hizmet kaldırılır. Aksi takdirde, tüm etkinlikleri kaldırılana kadar hizmet bağlı kalır. (Hizmet kaldırılmadan önce sonraki birstartService()
çağrısı alınırsa beklemedeki durdurma iptal edilir.)
Aşağıdaki akış şemasında, bir hizmetin yaşam döngüsünün nasıl yönetildiği gösterilmektedir. Değişken sayacı, bağlı istemcilerin sayısını izler:
MediaStyle bildirimlerini ön plan hizmetiyle kullanma
Oynatılan bir hizmet ön planda çalışıyor olmalıdır. Bu, sistemin, hizmetin yararlı bir işlev gerçekleştirdiğini ve sistemde bellek azsa kapatılmaması gerektiğini bilmesini sağlar. Ön plan hizmetlerinin, kullanıcının bundan haberdar olması ve isteğe bağlı olarak kontrol edebilmesi için bir bildirim görüntülemesi gerekir. onPlay()
geri çağırması, hizmeti ön plana almalıdır. (Bunun "ön plan"ın özel bir anlamı olduğunu unutmayın. Android, süreç yönetimi için hizmeti ön planda sayarken kullanıcıya başka bir uygulama "ön planda" görünürken oynatıcı arka planda oynar. dokunun.)
Bir hizmet ön planda çalışırken ideal olarak bir veya daha fazla aktarım kontrolüne sahip bir bildirim göstermelidir. Bildirimde oturumun meta verilerinden de yararlı bilgiler bulunmalıdır.
Oynatıcı oynamaya başladığında bildirim oluşturun ve görüntüleyin. Bunu yapmak için en iyi yer MediaSessionCompat.Callback.onPlay()
yönteminin içindedir.
Aşağıdaki örnekte
NotificationCompat.MediaStyle
,
Google Analytics 4'te tarama yapar. Meta veri ve aktarım denetimlerini gösteren bir bildirimin nasıl oluşturulacağı gösterilmektedir. Kolaylık yöntemi
getController()
.
doğrudan medya oturumunuzdan bir medya denetleyicisi oluşturmanızı sağlar.
Kotlin
// Given a media session and its context (usually the component containing the session) // Create a NotificationCompat.Builder // Get the session's metadata val controller = mediaSession.controller val mediaMetadata = controller.metadata val description = mediaMetadata.description val builder = NotificationCompat.Builder(context, channelId).apply { // Add the metadata for the currently playing track setContentTitle(description.title) setContentText(description.subtitle) setSubText(description.description) setLargeIcon(description.iconBitmap) // Enable launching the player by clicking the notification setContentIntent(controller.sessionActivity) // Stop the service when the notification is swiped away setDeleteIntent( MediaButtonReceiver.buildMediaButtonPendingIntent( context, PlaybackStateCompat.ACTION_STOP ) ) // Make the transport controls visible on the lockscreen setVisibility(NotificationCompat.VISIBILITY_PUBLIC) // Add an app icon and set its accent color // Be careful about the color setSmallIcon(R.drawable.notification_icon) color = ContextCompat.getColor(context, R.color.primaryDark) // Add a pause button addAction( NotificationCompat.Action( R.drawable.pause, getString(R.string.pause), MediaButtonReceiver.buildMediaButtonPendingIntent( context, PlaybackStateCompat.ACTION_PLAY_PAUSE ) ) ) // Take advantage of MediaStyle features setStyle(android.support.v4.media.app.NotificationCompat.MediaStyle() .setMediaSession(mediaSession.sessionToken) .setShowActionsInCompactView(0) // Add a cancel button .setShowCancelButton(true) .setCancelButtonIntent( MediaButtonReceiver.buildMediaButtonPendingIntent( context, PlaybackStateCompat.ACTION_STOP ) ) ) } // Display the notification and place the service in the foreground startForeground(id, builder.build())
Java
// Given a media session and its context (usually the component containing the session) // Create a NotificationCompat.Builder // Get the session's metadata MediaControllerCompat controller = mediaSession.getController(); MediaMetadataCompat mediaMetadata = controller.getMetadata(); MediaDescriptionCompat description = mediaMetadata.getDescription(); NotificationCompat.Builder builder = new NotificationCompat.Builder(context, channelId); builder // Add the metadata for the currently playing track .setContentTitle(description.getTitle()) .setContentText(description.getSubtitle()) .setSubText(description.getDescription()) .setLargeIcon(description.getIconBitmap()) // Enable launching the player by clicking the notification .setContentIntent(controller.getSessionActivity()) // Stop the service when the notification is swiped away .setDeleteIntent(MediaButtonReceiver.buildMediaButtonPendingIntent(context, PlaybackStateCompat.ACTION_STOP)) // Make the transport controls visible on the lockscreen .setVisibility(NotificationCompat.VISIBILITY_PUBLIC) // Add an app icon and set its accent color // Be careful about the color .setSmallIcon(R.drawable.notification_icon) .setColor(ContextCompat.getColor(context, R.color.primaryDark)) // Add a pause button .addAction(new NotificationCompat.Action( R.drawable.pause, getString(R.string.pause), MediaButtonReceiver.buildMediaButtonPendingIntent(context, PlaybackStateCompat.ACTION_PLAY_PAUSE))) // Take advantage of MediaStyle features .setStyle(new MediaStyle() .setMediaSession(mediaSession.getSessionToken()) .setShowActionsInCompactView(0) // Add a cancel button .setShowCancelButton(true) .setCancelButtonIntent(MediaButtonReceiver.buildMediaButtonPendingIntent(context, PlaybackStateCompat.ACTION_STOP))); // Display the notification and place the service in the foreground startForeground(id, builder.build());
MediaStyle bildirimlerini kullanırken bu NotificationCompat ayarları:
setContentIntent()
hizmetini kullanırken, bildirim aldığınızda hizmetiniz otomatik olarak başlatılır. bu pratik bir özelliktir.- "Güvenilmeyen" bir durum
kilit ekranında olduğu gibi, bildirim içeriklerinin varsayılan görünürlüğü
VISIBILITY_PRIVATE
şeklindedir. Bir sonraki videoda aktarma denetimlerinin olduğu içinVISIBILITY_PUBLIC
kullanmanız gerekir. - Arka plan rengini ayarlarken dikkatli olun. Normal bir bildirimle Android 5.0 veya sonraki sürümlerde, renk yalnızca küçük uygulama simgesi. Ancak, Android 7.0'dan önceki MediaStyle bildirimlerinde renk bildirim arka planının tamamı için kullanılır. Arka plan renginizi test edin. Git gözleri yumuşatın ve aşırı parlak veya floresan renklerden kaçının.
Bu ayarlar yalnızca NotificationCompat.MediaStyle'ı kullanırken kullanılabilir:
setMediaSession()
hesabını kullan tıklayın. Bu izin, üçüncü taraf uygulamalarına izin verir ve tamamlayıcı cihazlarla oturuma erişip kontrol edebilirsiniz.- Gösterilecek 3 işlem eklemek için
setShowActionsInCompactView()
kullanın bildirimin standart boyutlu contentView öğesine sahip olmasını sağlayabilirsiniz. (Duraklatma düğmesi şuradadır: belirtilir.) - Android 5.0 (API düzeyi 21) ve sonraki sürümlerde, bir bildirimi kaydırarak
oynatıcıyı kullanmaya devam edebilirsiniz. Yapamazsınız
bunu önceki sürümlerde yapacaksınız. Kullanıcıların bildirimi kaldırmasına ve oynatmayı durdurmasına izin vermek için
API düzeyi 21'den önceki sürümlerden önce sayfanın sağ üst köşesine bir iptal düğmesi ekleyebilirsiniz.
setShowCancelButton(true)
vesetCancelButtonIntent()
numaralı telefonu arayarak bildirim.
Duraklat ve iptal düğmelerini eklerken, ekleyeceğiniz bir PendingIntent'e
oynatma işlemiyle ilişkilendirir. MediaButtonReceiver.buildMediaButtonPendingIntent()
yöntemi dönüştürme işlemini yapar
PlaybackState işlemini PendingIntent'e dönüştürme.