赞
踩
目前主流的音视频App中,除了当用户正在使用时播放视频或音频,应用回到后台后音视频仍能继续播放的功能也很常见。本文简单介绍下如何使用Media3库实现在后台播放视频。
添加依赖
在app module下的build.gradle中添加代码,如下:
- dependencies {
- implementation("androidx.media3:media3-ui:1.1.0")
- implementation("androidx.media3:media3-session:1.1.0")
- implementation("androidx.media3:media3-exoplayer:1.1.0")
- }
在AndroidManifest
中添加前台服务权限,具体如下:
- <?xml version="1.0" encoding="utf-8"?>
- <manifest xmlns:android="http://schemas.android.com/apk/res/android">
-
- <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
-
- <!--targetSdk34开始需要添加此权限-->
- <uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" />
-
- ...
- </manifest>
前台服务权限按理来说需要动态申请,但是在测试过程中,发现没有动态申请也能实现在后台播放视频的功能。
自定义ExamplePlaybackService
继承MediaSessionService
,代码如下:
- class ExamplePlaybackService : MediaSessionService() {
-
- private var exoPlayer: ExoPlayer? = null
- private var mediaSession: MediaSession? = null
-
- override fun onCreate() {
- super.onCreate()
- // 创建ExoPlayer
- exoPlayer = ExoPlayer.Builder(this).build()
- // 基于已创建的ExoPlayer创建MediaSession
- exoPlayer?.let { mediaSession = MediaSession.Builder(this, it).build() }
- }
-
- override fun onDestroy() {
- // 释放相关实例
- exoPlayer?.stop()
- exoPlayer?.release()
- exoPlayer = null
- mediaSession?.release()
- mediaSession = null
- super.onDestroy()
- }
-
- override fun onGetSession(controllerInfo: MediaSession.ControllerInfo): MediaSession? {
- return mediaSession
- }
- }

在AndroidManifest
中添加ExamplePlaybackService
,代码如下:
- <?xml version="1.0" encoding="utf-8"?>
- <manifest xmlns:android="http://schemas.android.com/apk/res/android">
-
- ...
-
- <application
- ... >
-
- <!--android 10开始,需要指定foregroundServiceType-->
- <service
- android:name=".androidapi.media3.ExamplePlaybackService"
- android:exported="true"
- android:foregroundServiceType="mediaPlayback">
- <!--如果需要兼容低版本,需要添加此intent-filter-->
- <intent-filter>
- <action android:name="androidx.media3.session.MediaSessionService" />
- </intent-filter>
- </service>
- </application>
- </manifest>

播放视频
- class Media3ExampleActivity : AppCompatActivity() {
-
- private lateinit var binding: LayoutMedia3ExampleActivityBinding
-
- private lateinit var controllerFuture: ListenableFuture<MediaController>
- private val mediaController: MediaController?
- get() = if (controllerFuture.isDone) controllerFuture.get() else null
-
- private val playerListener = object : Player.Listener {
- override fun onIsPlayingChanged(isPlaying: Boolean) {
- super.onIsPlayingChanged(isPlaying)
- // 播放状态变化回调
- }
-
- override fun onPlaybackStateChanged(playbackState: Int) {
- super.onPlaybackStateChanged(playbackState)
- when (playbackState) {
- Player.STATE_IDLE -> {
- //播放器停止时的状态
- }
-
- Player.STATE_BUFFERING -> {
- // 正在缓冲数据
- }
-
- Player.STATE_READY -> {
- // 可以开始播放
- }
-
- Player.STATE_ENDED -> {
- // 播放结束
- }
- }
-
- }
-
- override fun onPlayerError(error: PlaybackException) {
- super.onPlayerError(error)
- // 获取播放错误信息
- }
- }
-
- @UnstableApi
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- binding = LayoutMedia3ExampleActivityBinding.inflate(layoutInflater)
- setContentView(binding.root)
- binding.includeTitle.tvTitle.text = "Media3 Example"
-
- binding.btnPlaySingleVideo.setOnClickListener {
- binding.playView.player?.run {
- // 停止之前播放的视频
- stop()
- //设置单个资源
- setMediaItem(MediaItem.fromUri("https://minigame.vip/Uploads/images/2021/09/18/1631951892_page_img.mp4"))
- // 开始缓冲
- prepare()
- }
- }
- binding.btnPlayMultiVideo.setOnClickListener {
- binding.playView.player?.run {
- // 停止之前播放的视频
- stop()
- // 设置多个资源,当一个视频播完后自动播放下一个
- setMediaItems(arrayListOf(
- MediaItem.fromUri("https://minigame.vip/Uploads/images/2021/09/18/1631951892_page_img.mp4"),
- MediaItem.fromUri("https://storage.googleapis.com/exoplayer-test-media-1/mp4/dizzy-with-tx3g.mp4")
- ))
- // 开始缓冲
- prepare()
- }
- }
- }
-
- private fun initController() {
- controllerFuture = MediaController.Builder(this, SessionToken(this, ComponentName(this, ExamplePlaybackService::class.java)))
- .buildAsync()
- controllerFuture.addListener({
- binding.root.post {
- mediaController?.let {
- binding.playView.player = it.apply {
- // 设置播放监听
- addListener(playerListener)
- // 设置重复模式
- // Player.REPEAT_MODE_ALL 无限重复
- // Player.REPEAT_MODE_ONE 重复一次
- // Player.REPEAT_MODE_OFF 不重复
- repeatMode = Player.REPEAT_MODE_ALL
- // 设置当缓冲完毕后直接播放视频
- playWhenReady = true
- }
- }
- }
- }, ContextCompat.getMainExecutor(this))
- }
-
- override fun onStart() {
- super.onStart()
- initController()
- }
-
- override fun onStop() {
- super.onStop()
- binding.playView.player = null
- MediaController.releaseFuture(controllerFuture)
- }
-
- override fun onDestroy() {
- super.onDestroy()
- // 释放播放器资源
- binding.playView.player?.release()
- binding.playView.player = null
- }
- }

效果如图:
可以看到,Media3库内部实现了用于播放的前台服务和通知,不用做额外的操作就可以简单的实现相关功能。
演示代码已在示例Demo中添加。
原文 Android Media3(二) - 在后台播放视频
★文末名片可以免费领取音视频开发学习资料,内容包括(FFmpeg ,webRTC ,rtmp ,hls ,rtsp ,ffplay ,srs)以及音视频学习路线图等等。
见下方!↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。