首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >双非大学生自学鸿蒙5.0零基础入门到项目实战--黑马云音乐下篇

双非大学生自学鸿蒙5.0零基础入门到项目实战--黑马云音乐下篇

作者头像
@VON
发布2025-12-21 12:29:29
发布2025-12-21 12:29:29
700
举报
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

前言

云音乐项目就剩最后一部分了,就是播控中心部分,今天上午看了下,感觉有点难,特别是对于不会看文档的小白来说确实有点难上手了,我在这里尽量讲解的通俗易懂,希望大家还是要学会读文档,会根据文档提示来学习,话不多说开始今天的学习

先把开发文档给到大家:开发文档

播控中心

在这里插入图片描述
在这里插入图片描述

后台播放

思路
在这里插入图片描述
在这里插入图片描述
创建会话

AVSession在构造方法中支持不同的类型参数,由 AVSessionType 定义,不同的类型代表了不同场景的控制能力,对于播控中心来说,会展示不同的控制模版。 audio类型,播控中心的控制样式为:收藏,上一首,播放/暂停,下一首,循环模式。 video类型,播控中心的控制样式为:快退,上一首,播放/暂停,下一首,快进。 voice_call类型,通话类型。

创建一个用于播控中心的工具类

在这里插入图片描述
在这里插入图片描述

初始化的时候就开始加载

在这里插入图片描述
在这里插入图片描述
长时任务

应用退至后台后,在后台需要长时间运行用户可感知的任务,如播放音乐、导航等。为防止应用进程被挂起,导致对应功能异常,可以申请长时任务,使应用在后台长时间运行。在长时任务中,支持同时申请多种类型的任务,也可以对任务类型进行更新。应用退至后台执行业务时,系统会做一致性校验,确保应用在执行相应的长时任务。应用在申请长时任务成功后,通知栏会显示与长时任务相关联的消息,用户删除通知栏消息时,系统会自动停止长时任务。

先申请权限

在这里插入图片描述
在这里插入图片描述

声明后台模式类型

在这里插入图片描述
在这里插入图片描述

申请长时任务逻辑

在这里插入图片描述
在这里插入图片描述

在播放歌曲的时候使用

在这里插入图片描述
在这里插入图片描述
测试

实现了歌曲可以在后台进行播放的功能

在这里插入图片描述
在这里插入图片描述

同步音乐

设置元数据

应用可以通过setAVMetadata把会话的一些元数据信息设置给系统,从而在播控中心界面进行展示,包括不限制:当前媒体的ID(assetId),上一首媒体的ID(previousAssetId),下一首媒体的ID(nextAssetId),标题(title),专辑作者(author),专辑名称(album),词作者(writer),媒体时长(duration)等。

就是设置一下所用到的数据

在这里插入图片描述
在这里插入图片描述

在时间变化这里添加以下即可

在这里插入图片描述
在这里插入图片描述
设置播放状态

应用可以通过setAVPlaybackState。把当前的播放状态设置给系统,以在播控中心界面进行展示。 播放状态一般是在资源播放后会进行变化的内容,包括:当前媒体的播放状态(state)、播放位置(position)、播放倍速(speed)、缓冲时间(bufferedTime)、循环模式(loopMode)、是否收藏(isFavorite)、正在播放的媒体Id(activeItemId)、自定义媒体数据(extras)等。

核心逻辑如下,这里有三个地方需要设置播放状态

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
注册事件

应用接入AVSession,可以通过注册不同的控制命令来实现播控中心界面上的控制操作,即通过on接口注册不同的控制命令参数,即可实现对应的功能。

在这里插入图片描述
在这里插入图片描述
注销会话

一定要注销会话释放资源

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

结尾

这部分内容确实有点难以理解,课下还是要去再慢慢琢磨琢磨,感觉还是思路有点乱,感兴趣的可以仔细看一下这两个工具类中的代码,我这里就不意义解释了

代码

AvSessionManager代码

代码语言:javascript
复制
import { avSession } from '@kit.AVSessionKit'
import { wantAgent } from '@kit.AbilityKit';
import backgroundTaskManager from '@ohos.resourceschedule.backgroundTaskManager';
import { GlobalMusic } from '../models/globalMusic';
import { AppStorageV2 } from '@kit.ArkUI';
import { SongItemType } from '../models/music';
import { playerManager } from './AvPlayerManager';

class AvSessionManager{
  session : avSession.AVSession | null = null
  playState:GlobalMusic = AppStorageV2.connect(GlobalMusic,'SONG_KEY',()=>new GlobalMusic())!


  async init(content:Context){
    this.session = await avSession.createAVSession(content,'bgPlay','audio')
    this.registerEvent()
  }

  // 申请长时任务
  async startBackGroundTask(){
    let wantAgentInfo: wantAgent.WantAgentInfo = {
      wants: [
        {
          bundleName: "com.example.von_music",
          abilityName: "EntryAbility"
        }
      ],
      actionType: wantAgent.OperationType.START_ABILITY,
      requestCode: 0,
      actionFlags: [wantAgent.WantAgentFlags.UPDATE_PRESENT_FLAG],
    };
    const want = await wantAgent.getWantAgent(wantAgentInfo)
    await backgroundTaskManager.startBackgroundRunning(getContext(),backgroundTaskManager.BackgroundMode.AUDIO_PLAYBACK,want)
  }

  // 设置元数据
  setAVMetadata(song:SongItemType){
    this.session?.setAVMetadata({
      assetId:song.id,
      title:song.name,
      mediaImage:song.img,
      artist:song.author,
      duration:this.playState.duration
    })
  }

  // 设置播放状态
  setAVPlayBackState(){
    this.session?.setAVPlaybackState({
      state:this.playState.isPlay ? avSession.PlaybackState.PLAYBACK_STATE_PLAY : avSession.PlaybackState.PLAYBACK_STATE_PAUSE,
      speed:1,
      position:{
        elapsedTime:this.playState.time,//歌曲播放时间
        updateTime:new Date().getTime()//系统时间
      },
      duration:this.playState.duration
    })
  }

  // 注册事件
  registerEvent(){
    this.session?.on('play',()=>{
      playerManager.singPlay(this.playState.playList[this.playState.playIndex])
    })
    this.session?.on('pause',()=>{
      playerManager.paused()
    })
    this.session?.on('playPrevious',()=>{
      playerManager.prevPlay()
    })
    this.session?.on('playNext',()=>{
      playerManager.nextPlay()
    })
    this.session?.on('seek',(value:number)=>{
      playerManager.seekPlay(value)
    })
    this.session?.activate()
  }

  // 注销会话
  async destroy(){
    await this.session?.destroy()
  }

}

export const sessionManager : AvSessionManager = new AvSessionManager()

AvPlayerManager代码

代码语言:javascript
复制
import { media } from '@kit.MediaKit'
import { GlobalMusic } from '../models/globalMusic'
import { SongItemType } from '../models/music'
import { AppStorageV2 } from '@kit.ArkUI'
import { sessionManager } from './AvSessionManager'

class AvPlayerManager{
  // 播放器
  player : media.AVPlayer | null = null
  currentSong : GlobalMusic = AppStorageV2.connect(GlobalMusic,'SONG_KEY',()=>new GlobalMusic())!

  // 定义方法
  async init () {
    if(!this.player){
      this.player = await media.createAVPlayer()
    }
    // 监听状态变化
    this.player.on('stateChange',(state) => {
      if(state === 'initialized'){
        this.player?.prepare()
      }else if(state === 'prepared'){
        this.player?.play()
        this.currentSong.isPlay = true
      } else if(state === 'completed'){
        this.nextPlay(true)
      } else if(state === 'released'){
        this.currentSong.reset()
      }
    })

    // 监听时间变化
    this.player.on('durationUpdate',(duration)=>{
      this.currentSong.duration = duration
      sessionManager.setAVMetadata((this.currentSong.playList[this.currentSong.playIndex]))
    })
    this.player.on('timeUpdate',(time)=>{
      this.currentSong.time = time
      sessionManager.setAVPlayBackState()
    })

  }

  // 播放歌曲
  singPlay(song:SongItemType){
    // 申请长时任务
    sessionManager.startBackGroundTask()
    sessionManager.setAVPlayBackState()
    const inList = this.currentSong.playList.some(item => item.id === song.id)
    // 歌曲在列表里
    if(inList){
      // 正在播放
      if(this.currentSong.url === song.url){
        this.player?.play()
        this.currentSong.isPlay = true
      }else {
        // 如果没有播放根据索引找到歌曲进行播放
        this.currentSong.playIndex = this.currentSong.playList.findIndex(item => item.id === song.id)

        // 切歌
        this.changeSong()
      }
    } else { // 歌曲不在列表
      this.currentSong.playList.unshift(song) // 将歌曲添加到列表并且设置为索引为0
      this.currentSong.playIndex = 0
      // 切歌
      this.changeSong()
    }
  }

  // 切歌
  async changeSong() {
    await this.player?.reset()
    this.currentSong.duration = 0
    this.currentSong.time = 0
    this.currentSong.img = this.currentSong.playList[this.currentSong.playIndex].img
    this.currentSong.name = this.currentSong.playList[this.currentSong.playIndex].name
    this.currentSong.author = this.currentSong.playList[this.currentSong.playIndex].author
    this.currentSong.url = this.currentSong.playList[this.currentSong.playIndex].url
    this.player!.url = this.currentSong.url
  }

  // 跳转进度 seek
  seekPlay(value:number){
    this.player?.seek(value)
  }

  // 暂停
  paused() {
    this.player?.pause()
    this.currentSong.isPlay = false
    sessionManager.setAVPlayBackState()

  }

  // 上一首
  prevPlay(){
    if(this.currentSong.playMode === 'random'){
      // 随机播放
      // Math.random : [0,1)
      this.currentSong.playIndex = Math.floor(Math.random() * this.currentSong.playList.length)
    }else {
      this.currentSong.playIndex--
      if(this.currentSong.playIndex < 0){
        this.currentSong.playIndex = this.currentSong.playList.length - 1
      }
    }
    this.singPlay(this.currentSong.playList[this.currentSong.playIndex])
  }

  // 下一首
  nextPlay(autoNextPlay ?: boolean){
    if(this.currentSong.playMode === 'repeat' && autoNextPlay){// 重复播放:当前模式为repeat并且autoNextPlay为true
      this.currentSong.playIndex = this.currentSong.playIndex
    }else if(this.currentSong.playMode === 'random'){
      // 随机播放
      // Math.random : [0,1)
      this.currentSong.playIndex = Math.floor(Math.random() * this.currentSong.playList.length)
    } else {
      this.currentSong.playIndex++
      if(this.currentSong.playIndex >=  this.currentSong.playList.length){
        this.currentSong.playIndex = 0
      }
    }
    this.singPlay(this.currentSong.playList[this.currentSong.playIndex])
  }

  // 列表移除歌曲
  removeSong(index:number){
    if(index === this.currentSong.playIndex){
      // 删除的是正在播放的歌曲
      if(this.currentSong.playList.length > 1){
        // 列表有多首歌
        this.currentSong.playList.splice(index,1)
        // 目前播放的歌曲的最后一首
        if(this.currentSong.playIndex >= this.currentSong.playList.length){
          this.currentSong.playIndex = 0
        }
        this.singPlay(this.currentSong.playList[this.currentSong.playIndex])
      }else{
        // 列表只有一首歌
        this.player?.reset()
        this.currentSong.reset()
      }
    } else {
      if(index < this.currentSong.playIndex){
        // 要删除歌曲在播放的前面
        this.currentSong.playIndex--
      }
      this.currentSong.playList.splice(index,1)
    }
  }

  // 释放播放器
  async release() {
    await this.player?.release()
  }
}

export const playerManager : AvPlayerManager = new AvPlayerManager()
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-11-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 播控中心
    • 后台播放
      • 思路
      • 创建会话
      • 长时任务
      • 测试
    • 同步音乐
      • 设置元数据
      • 设置播放状态
      • 注册事件
      • 注销会话
  • 结尾
  • 代码
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档