我使用 Media3 1.0.0-beta03 构建了一个网络广播播放器。我使用来自的示例代码 开发者页面。
它自动生成了媒体通知,但我不知道如何为其添加标题和副标题。
这是我的媒体服务:
class PlaybackService : MediaSessionService(), MediaSession.Callback {
private object LC {
lateinit var exoPlayer: ExoPlayer
lateinit var mediaSession: MediaSession
}
override fun onCreate() {
super.onCreate()
log("----------------------------- MediaSessionService, onCreate")
LC.exoPlayer = ExoPlayer.Builder(this).build()
LC.exoPlayer.addListener(ExoListener())
LC.exoPlayer.setAudioAttributes(AudioAttributes.Builder().setContentType(AUDIO_CONTENT_TYPE_MUSIC).setUsage(USAGE_MEDIA).build(),true)
LC.mediaSession = MediaSession.Builder(this, LC.exoPlayer).setCallback(this).build()
}
override fun onGetSession(controllerInfo: MediaSession.ControllerInfo): MediaSession = LC.mediaSession
override fun onAddMediaItems(mediaSession: MediaSession, controller: MediaSession.ControllerInfo, mediaItems: MutableList<MediaItem>): ListenableFuture<MutableList<MediaItem>> {
val updatedMediaItems = mediaItems.map { it.buildUpon().setUri(it.mediaId).build() }.toMutableList()
return Futures.immediateFuture(updatedMediaItems)
}
override fun onDestroy() {
log("----------------------------- MediaSessionService, onDestroy")
LC.exoPlayer.stop()
LC.exoPlayer.release()
LC.mediaSession.release()
super.onDestroy()
exitProcess(0)
}
}
我尝试了 onUpdateNotification
更新:
还有另一种方法,我发现它可以更好地完成工作。
在MediaSessionService的onCreate()函数中,我们可以像这样设置一个MediaNotificationProvider。
private lateinit var nBuilder: NotificationCompat.Builder
override fun onCreate(){
super.onCreate()
// init notificationCompat.Builder before setting the MediaNotificationProvider
this.setMediaNotificationProvider(object : MediaNotification.Provider{
override fun createNotification(
mediaSession: MediaSession,// this is the session we pass to style
customLayout: ImmutableList<CommandButton>,
actionFactory: MediaNotification.ActionFactory,
onNotificationChangedCallback: MediaNotification.Provider.Callback
): MediaNotification {
createNotification(mediaSession)
// notification should be created before you return here
return MediaNotification(NOTIFICATION_ID,nBuilder.build())
}
override fun handleCustomCommand(
session: MediaSession,
action: String,
extras: Bundle
): Boolean {
TODO("Not yet implemented")
}
})
}
fun createNotification(session: MediaSession) {
val notificationManager: NotificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
notificationManager.createNotificationChannel(NotificationChannel(notification_id,"Channel", NotificationManager.IMPORTANCE_LOW))
// NotificationCompat.Builder here.
nBuilder = NotificationCompat.Builder(this,notification_id)
// Text can be set here
// but I believe setting MediaMetaData to MediaSession would be enough.
// I havent tested it deeply yet but did display artist from session
.setSmallIcon(R.drawable.your_drawable)
.setContentTitle("your Content title")
.setContentText("your content text")
// set session here
.setStyle(MediaStyleNotificationHelper.MediaStyle(session))
// we don build.
}
最后,如果您想自己更新通知信息
您可以通过调用这样的函数来做到这一点..
private fun updateNotification(/*parameter*/){
nBuilder.setContentTitle("text")
nBuilder.setContentText("subtext")
nManager.notify(NOTIFICATION_ID,nBuilder.build())
}
如果您担心只更新通知的标题和副标题,则覆盖自动通知可能不是一个好主意,因为您可以节省大量代码行。 您是否尝试过设置通知中显示的 mediaItem 的元数据?因为如果未提供元数据,Android 将获取文件的嵌入元数据并显示。您可以通过 -
设置元数据fun getMetaDataFromMediaClass(media: MediaClass): MediaMetadata {
return MediaMetadata.Builder()
.setTitle(media.title)
.setAlbumTitle(media.title)
.setDisplayTitle(media.title)
.setArtist(media.subtitle)
.setAlbumArtist(media.subtitle)
.setArtworkUri(media.imageURL.toUri())
.build()
}
fun performPlayMedia(media: MediaClass) {
val metadata = getMetaDataFromMediaClass(media)
val mediaItem = MediaItem.Builder()
.setUri(media.dataURL)
.setMediaId(media.mediaID)
.setMediaMetadata(metadata)
.build()
player.apply {
setMediaItem(mediaItem)
prepare()
play()
}
}
是的,谢谢TG。卡赛
不需要通知管理器。
class PlaybackService : MediaSessionService(), MediaSession.Callback {
private object LC {
lateinit var exoPlayer: ExoPlayer
lateinit var mediaSession: MediaSession
}
@SuppressLint("UnsafeOptInUsageError")
override fun onCreate() {
super.onCreate()
log("----------------------------- MediaSessionService, onCreate")
LC.exoPlayer = ExoPlayer.Builder(this).build()
LC.exoPlayer.addListener(BackgroundService())
LC.exoPlayer.setAudioAttributes(AudioAttributes.Builder().setContentType(AUDIO_CONTENT_TYPE_MUSIC).setUsage(USAGE_MEDIA).build(),true)
LC.mediaSession = MediaSession.Builder(this, LC.exoPlayer).setCallback(this).build()
setMediaNotificationProvider(object : MediaNotification.Provider{
override fun createNotification(
mediaSession: MediaSession,
customLayout: ImmutableList<CommandButton>,
actionFactory: MediaNotification.ActionFactory,
onNotificationChangedCallback: MediaNotification.Provider.Callback
): MediaNotification {
// This run every time when I press buttons on notification bar:
return updateNotification(mediaSession)
}
override fun handleCustomCommand(session: MediaSession, action: String, extras: Bundle): Boolean { return false }
})
}
@SuppressLint("UnsafeOptInUsageError")
private fun updateNotification(session: MediaSession): MediaNotification {
val notify = NotificationCompat.Builder(this,"Radio")
.setSmallIcon(R.drawable.ic_launcher_foreground)
// This is globally changed every time when
// I add a new MediaItem from background service
.setContentTitle(GL.MEDIA.radio)
.setContentText(GL.MEDIA.artist)
.setStyle(MediaStyleNotificationHelper.MediaStyle(session))
.build()
return MediaNotification(1, notify)
}
override fun onGetSession(controllerInfo: MediaSession.ControllerInfo): MediaSession = LC.mediaSession
override fun onAddMediaItems(mediaSession: MediaSession, controller: MediaSession.ControllerInfo, mediaItems: MutableList<MediaItem>): ListenableFuture<MutableList<MediaItem>> {
val updatedMediaItems = mediaItems.map { it.buildUpon().setUri(it.mediaId).build() }.toMutableList()
return Futures.immediateFuture(updatedMediaItems)
}
override fun onDestroy() {
log("----------------------------- MediaSessionService, onDestroy")
LC.exoPlayer.stop()
LC.exoPlayer.release()
LC.mediaSession.release()
super.onDestroy()
}
}
事实证明,非常简单。
MediaService 类中有一个需要重写的方法,称为 onUpdateNotification()。它为我们提供了媒体会议。
所以我们可以覆盖它并创建我们自己的NotificationCompat
// Override this method in your service
override fun onUpdateNotification(session: MediaSession) {
createNotification(session) //calling method where we create notification
}
在 createNotification() 方法中,我们创建通知并使用 MediaStyleHelper.MediaStyle() 设置其样式,并在那里设置会话参数 就像下面这样。
并一如既往地创建通知
fun createNotification(session: MediaSession) {
val notificationManager: NotificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
notificationManager.createNotificationChannel(NotificationChannel(notification_id,"Channel", NotificationManager.IMPORTANCE_LOW))
// NotificationCompat here.
val notificationCompat = NotificationCompat.Builder(this,notification_id)
// Text can be set here
// but I believe setting MediaMetaData to MediaSession would be enough.
// I havent tested it deeply yet but did display artist from session
.setSmallIcon(R.drawable.your_drawable)
.setContentTitle("your Content title")
.setContentText("your content text")
// set session here
.setStyle(MediaStyleNotificationHelper.MediaStyle(session))
.build()
notificationManager.notify(1,notificationCompat)
}
我希望这会有所帮助,而且还为时不晚。
编辑:
另一个更简洁的选择是仅使用所需的 MediaMetaData 创建 MediaItem 并将其添加到 ExoPlayer。如果来源是 Hls,请尝试不要向 MediaMetaData 添加标题。
根据我的测试,与之前的 Android 版本相比,Android 13 中媒体样式通知提供的信息非常有限,并且发生了很大的变化。除了 METADATA_KEY_ART 之外,还显示 TITLE 或 DISPLAY_TITLE,而后者是首选。还显示了艺术家。另一方面,SUBTITLE 甚至 ALBUM 和 COMPOSER 都被忽略,同时浪费了大量的屏幕空间。这使得媒体风格通知实际上无法用于不流行(即非流行)音乐。并确保元数据分配给媒体会话,而不是通知本身。