如何将我的前台服务通知 (MediaStyle) 保持在顶部,如 Google 播放音乐?
How to keep my foreground service notification (MediaStyle) on top like Google Play Music?
所以,我有一个 PlayerService,它基本上是一个音频播放器。它位于前台,并使用 MediaStyle 和自定义操作(通知中的按钮),如上一个、play/pause、下一个和关闭。
问题是,当我启动 Google Play Music 等其他音频应用程序时,它的通知总是在我的上方!如果我用我的其他 2 个音频应用程序启动,当我单击它们通知中的播放图标时,该通知会转到顶部并停留在那里。而我的总是倒数第二。我的应用程序是否正在播放并不重要。
尝试了 API 的所有版本。但是假设我主要将它与 pre-Oreo 一起使用,所以我们可以忘记 NotificationChannel 的东西。
也试过用MediaSession,设置PRIORITY_MAX,还是不行。顺便说一句,AudioFocus 和所有其他东西都运行良好。通知优先级是唯一的问题。
getNotification() 方法:
return NotificationCompat.Builder( this, CHANNEL_ID )
.setTicker(ticker)
.setContentTitle(title)
.setContentText(text)
.setSmallIcon(icon)
.setLargeIcon(icon)
.setContentIntent(notificationPendingIntent)
.addAction(prevAction)
.addAction(playAction)
.addAction(nextAction)
.addAction(stopAction)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setStyle(androidx.media.app.NotificationCompat.MediaStyle()
.setShowActionsInCompactView(0, 1, 2)
)
.setColor(color)
.setWhen(System.currentTimeMillis())
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
.build()
更新为:
notificationManager.notify( 1, getNotification() )
动作示例:
NotificationCompat.Action(
R.drawable.play,
"Play",
PendingIntent.getBroadcast(
this,
REQUEST_CODE,
playIntent,
PendingIntent.FLAG_UPDATE_CURRENT
)
)
所以,问题出在 MediaSession API 的某个地方。我试图在一些教程和 Google 文档的帮助下让它工作,但失败了。其中一些太难或太矫枉过正(例如 Github 上的 UniversalMusicPlayer)。我不需要用 Android Auto 等实现所有这些东西。
终于,我找到了 Exoplayer MediaSession 扩展。这就是我的做法。
build.gradle:
implementation 'com.google.android.exoplayer:extension-mediasession:2.10.1'
清单:
<receiver android:name="androidx.media.session.MediaButtonReceiver">
<intent-filter>
<action android:name="android.intent.action.MEDIA_BUTTON"/>
</intent-filter>
</receiver>
PlayerService.kt:
...
private val player by lazy { ExoPlayerFactory.newSimpleInstance( this ) }
private val mediaSession by lazy { MediaSessionCompat(this, TAG) }
private val connector by lazy { MediaSessionConnector(mediaSession) }
...
override fun onCreate() {
super.onCreate()
mediaSession.setFlags( MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS or MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS )
connector.setPlayer(player)
}
...
private fun getNotification(): Notification {
return NotificationCompat.Builder( this, CHANNEL_ID )
...
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setStyle(androidx.media.app.NotificationCompat.MediaStyle()
.setMediaSession(mediaSession.sessionToken)
.setShowActionsInCompactView(0, 1, 2)
)
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
.build()
}
这里最重要的部分是连接器。其他代码就像任何其他前台或音频服务一样。但是 MediaSessionConnector 在这里是一个东西。只需几行,但可以为您处理所有事情。您不必编写其他一些 Media*** 代码!除了 MediaBrowser 的东西,但它不是我的情况。
只是因为你没有注册MediaSession
mMediaSession = new MediaSessionCompat(mContext, TAG, mComponentName, null);
别忘了
mMediaSession.setPlaybackState(new PlaybackStateCompat.Builder()
.setState(PlaybackStateCompat.STATE_PLAYING, 0, 1.0f)
.build());
所以,我有一个 PlayerService,它基本上是一个音频播放器。它位于前台,并使用 MediaStyle 和自定义操作(通知中的按钮),如上一个、play/pause、下一个和关闭。
问题是,当我启动 Google Play Music 等其他音频应用程序时,它的通知总是在我的上方!如果我用我的其他 2 个音频应用程序启动,当我单击它们通知中的播放图标时,该通知会转到顶部并停留在那里。而我的总是倒数第二。我的应用程序是否正在播放并不重要。
尝试了 API 的所有版本。但是假设我主要将它与 pre-Oreo 一起使用,所以我们可以忘记 NotificationChannel 的东西。
也试过用MediaSession,设置PRIORITY_MAX,还是不行。顺便说一句,AudioFocus 和所有其他东西都运行良好。通知优先级是唯一的问题。
getNotification() 方法:
return NotificationCompat.Builder( this, CHANNEL_ID )
.setTicker(ticker)
.setContentTitle(title)
.setContentText(text)
.setSmallIcon(icon)
.setLargeIcon(icon)
.setContentIntent(notificationPendingIntent)
.addAction(prevAction)
.addAction(playAction)
.addAction(nextAction)
.addAction(stopAction)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setStyle(androidx.media.app.NotificationCompat.MediaStyle()
.setShowActionsInCompactView(0, 1, 2)
)
.setColor(color)
.setWhen(System.currentTimeMillis())
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
.build()
更新为:
notificationManager.notify( 1, getNotification() )
动作示例:
NotificationCompat.Action(
R.drawable.play,
"Play",
PendingIntent.getBroadcast(
this,
REQUEST_CODE,
playIntent,
PendingIntent.FLAG_UPDATE_CURRENT
)
)
所以,问题出在 MediaSession API 的某个地方。我试图在一些教程和 Google 文档的帮助下让它工作,但失败了。其中一些太难或太矫枉过正(例如 Github 上的 UniversalMusicPlayer)。我不需要用 Android Auto 等实现所有这些东西。
终于,我找到了 Exoplayer MediaSession 扩展。这就是我的做法。
build.gradle:
implementation 'com.google.android.exoplayer:extension-mediasession:2.10.1'
清单:
<receiver android:name="androidx.media.session.MediaButtonReceiver">
<intent-filter>
<action android:name="android.intent.action.MEDIA_BUTTON"/>
</intent-filter>
</receiver>
PlayerService.kt:
...
private val player by lazy { ExoPlayerFactory.newSimpleInstance( this ) }
private val mediaSession by lazy { MediaSessionCompat(this, TAG) }
private val connector by lazy { MediaSessionConnector(mediaSession) }
...
override fun onCreate() {
super.onCreate()
mediaSession.setFlags( MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS or MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS )
connector.setPlayer(player)
}
...
private fun getNotification(): Notification {
return NotificationCompat.Builder( this, CHANNEL_ID )
...
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setStyle(androidx.media.app.NotificationCompat.MediaStyle()
.setMediaSession(mediaSession.sessionToken)
.setShowActionsInCompactView(0, 1, 2)
)
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
.build()
}
这里最重要的部分是连接器。其他代码就像任何其他前台或音频服务一样。但是 MediaSessionConnector 在这里是一个东西。只需几行,但可以为您处理所有事情。您不必编写其他一些 Media*** 代码!除了 MediaBrowser 的东西,但它不是我的情况。
只是因为你没有注册MediaSession
mMediaSession = new MediaSessionCompat(mContext, TAG, mComponentName, null);
别忘了
mMediaSession.setPlaybackState(new PlaybackStateCompat.Builder()
.setState(PlaybackStateCompat.STATE_PLAYING, 0, 1.0f)
.build());