鸿蒙应用开发之通过AVPlayer如何实现音乐播放、暂停、音量设置?

效果展示

实现思路

  • 传统操作音乐播放:传统写项目(淘宝京东)就是一个个html文件,里面写Javascript代码(切记不允许全部看代码,看大步骤)

1 获取音乐对象 player

2 调用api 播放play、暂定pause等等

ini 复制代码
<audio
  controls
  src="http://tmp00002.zhaodashen.cn/mp3/chenyixun_000z2oXY18Hsli.m4a"
></audio>

<button id="playerBtn">播放</button>
<button id="pausereBtn">暂停</button>
<script>
  // 1 获取实例
  const player = document.querySelector("audio");
  //   console.log("player::: ", player);
  // 2 调用api播放
  playerBtn.onclick = () => {
    player.play();
  };
  pausereBtn.onclick = () => {
    player.pause();
  };
</script>
  • 鸿蒙操作音乐播放语法
javascript 复制代码
import {media} from '@kit.MediaKit'


// ✅ 1. 创建音乐播放器对象
const player:media.AVPlayer  = await media.createAVPlayer()

// ✅ 2. 侦听播放状态(监控设置地址)
player.on('stateChange', (state) => {
    switch(state) {
        // 初始化状态
        case 'initialized':
            player.prepare() // 准备就绪态
            break;
        // 准备就绪态
        case 'prepared':
            player.play() // 播放
            break;
    }
})
player.on('durationUpdate', (duration) => {}) // 歌曲时长
player.on('timeUpdate', (data) => {}) 				// 播放时长
player.on('volumeChange', () => {})  // 音量


// ✅ 3. 调用API控制状态

// - 播放地址
player.url = 播放源地址

// - 切换播放地址
await player.reset()
player.url = 播放源地址

// - 暂停
player.pause()

// - 音量
player.setVolume(0~1范围)

// - 循环播放
player.loop = 布尔

// - 播放速率
player.setSpeed(media.PlaybackSpeed.SPEED_FORWARD_0_75_X)
player.setSpeed(media.PlaybackSpeed.SPEED_FORWARD_1_00_X)
player.setSpeed(media.PlaybackSpeed.SPEED_FORWARD_1_25_X)
player.setSpeed(media.PlaybackSpeed.SPEED_FORWARD_1_75_X)
player.setSpeed(media.PlaybackSpeed.SPEED_FORWARD_2_00_X)

// - 本地播放
//这里的音频资源是放在rawfile文件夹中的.mp3文件,读者自己设置其他文件资源。
//给播放器设置播放资源,上图有参考资料,使用的是fsSrc资源,不是网络资源->。
const fd = getContext().resourceManager.getRawFdSync(name)
this.avplayer.fdSrc = { fd: fd.fd, offset: fd.offset, length: fd.length }

完整代码

ini 复制代码
import {media} from '@kit.MediaKit'


export class DateUtil {
  static m2s(ms:number) {
    // 分钟 = parseInt(总毫秒/1000/60) 得到分钟然后不够补0    这个parseInt是为了去掉小数
    const m = parseInt(String(ms/1000/60)).toString().padStart(2,'0');
    // 秒数 = parseInt(总毫秒/100得到秒 - 分占用的秒)   最终秒数  不够补0
    // const s = parseInt(String(ms/1000 - parseInt(m)*60)).toString().padStart(2,'0')
    const s = parseInt(String(ms/1000%60)).toString().padStart(2,'0')
    return `${m}:${s}`
  }
}


@Entry
@Component
struct Index {

  // "[al:认了吧]"
  // "[00:00.00]爱情转移 - 陈奕迅 (Eason Chan)"
  // "[00:05.73]词:林夕"
  @State currentLrc:string = ''
  private lrc: string[] = "[ti:爱情转移 (《爱情呼叫转移》电影主题曲|《富士山下》国语版)]\n[ar:陈奕迅]\n[al:认了吧]\n[by:]\n[offset:0]\n[00:00.00]爱情转移 - 陈奕迅 (Eason Chan)\n[00:05.73]词:林夕\n[00:11.47]曲:泽日生\n[00:17.21]编曲:陈珀/C.Y.Kong\n[00:22.95]徘徊过多少橱窗\n[00:25.29]住过多少旅馆\n[00:27.54]才会觉得分离也并不冤枉\n[00:31.89]感情是用来浏览\n[00:34.15]还是用来珍藏\n[00:36.55]好让日子天天都过得难忘\n[00:40.98]熬过了多久患难\n[00:43.37]湿了多少眼眶\n[00:45.63]才能知道伤感是爱的遗产\n[00:50.22]流浪几张双人床\n[00:52.63]换过几次信仰\n[00:54.77]才让戒指义无反顾的交换\n[00:59.28]把一个人的温暖\n[01:01.70]转移到另一个的胸膛\n[01:04.74]让上次犯的错反省出梦想\n[01:08.48]\n[01:08.98]每个人都是这样\n[01:11.27]享受过提心吊胆\n[01:13.74]才拒绝做爱情待罪的羔羊\n[01:18.21]回忆是抓不到的月光握紧就变黑暗\n[01:22.84]等虚假的背影消失于晴朗\n[01:26.67]\n[01:27.34]阳光在身上流转\n[01:29.53]等所有业障被原谅\n[01:32.62]\n[01:34.94]爱情不停站\n[01:36.78]想开往地老天荒\n[01:39.34]需要多勇敢\n[01:41.35]\n[01:43.58]烛光照亮了晚餐\n[01:45.95]照不出个答案\n[01:48.20]恋爱不是温馨的请客吃饭\n[01:52.18]\n[01:52.69]床单上铺满花瓣\n[01:55.11]拥抱让它成长\n[01:57.33]太拥挤就开到了别的土壤\n[02:01.79]感情需要人接班\n[02:04.22]接近换来期望\n[02:06.51]期望带来失望的恶性循环\n[02:10.96]短暂的总是浪漫\n[02:13.31]漫长总会不满\n[02:15.57]烧完美好青春换一个老伴\n[02:19.59]\n[02:20.12]把一个人的温暖\n[02:22.45]转移到另一个的胸膛\n[02:25.28]让上次犯的错反省出梦想\n[02:29.14]\n[02:29.86]每个人都是这样\n[02:32.03]享受过提心吊胆\n[02:34.42]才拒绝做爱情待罪的羔羊\n[02:39.01]回忆是抓不到的月光握紧就变黑暗\n[02:43.54]等虚假的背影消失于晴朗\n[02:47.43]\n[02:48.08]阳光在身上流转\n[02:50.38]等所有业障被原谅\n[02:53.37]\n[02:54.86]爱情不停站\n[02:56.83]想开往地老天荒\n[02:59.79]需要多勇敢\n[03:01.88]\n[03:04.22]把一个人的温暖\n[03:06.75]转移到另一个的胸膛\n[03:09.60]让上次犯的错反省出梦想\n[03:13.70]\n[03:14.21]每个人都是这样\n[03:16.61]享受过提心吊胆\n[03:19.08]才拒绝做爱情待罪的羔羊\n[03:23.82]回忆是抓不到的月光握紧就变黑暗\n[03:28.46]等虚假的背影消失于晴朗\n[03:32.54]\n[03:33.11]阳光在身上流转\n[03:35.47]等所有业障被原谅\n[03:38.67]\n[03:42.48]爱情不停站\n[03:44.28]想开往地老天荒\n[03:47.24]\n[03:47.82]需要多勇敢\n[03:50.26]\n[03:53.07]你不要失望\n[03:54.75]荡气回肠是为了\n[03:57.64]最美的平凡".split('\n')


  @State duration:number = 0
  @State currentTime:number = 0

  // private player: media.AVPlayer = {} as media.AVPlayer
  // private player: media.AVPlayer = {} as ESObject
  private player: media.AVPlayer = Object()


  async aboutToAppear() {
    // ✅ 1. 创建音乐播放器对象
    // const player:media.AVPlayer  = await media.createAVPlayer()  切记player放外面 后期要操作
    this.player = await media.createAVPlayer()

    // ✅ 2. 侦听播放状态
    this.player.on('stateChange', (state) => {
      switch(state) {
        // 初始化状态
        case 'initialized':
          console.log('11111 initialized')
          this.player.prepare() // 准备就绪态
          break;
        // 准备就绪态
        case 'prepared':
          console.log('2222 prepared')
          this.player.play() // 播放
          break;
      }
    })
    this.player.on('durationUpdate', (duration) => { // 歌曲时长
      console.log('歌曲时长:', duration)
      this.duration = duration
    })
    this.player.on('timeUpdate', (time) => {  // 播放时长
      console.log('播放时长:', time)
      this.currentTime = time

      for (let i=0; i<this.lrc.length; i++) {
        const item = this.lrc[i]
        const m2s = item.slice(1,6)  // '01:11'
        if (DateUtil.m2s(time) === m2s) {
          this.currentLrc = item.slice(10)
        }
      }
    })
    // this.player.on('volumeChange', () => {})  // 音量
  }
  build() {
    Column() {
      Text('hello music').fontSize(30)


      Button('打开界面(设置播放链接)').onClick(() => {
        this.player.url = 'http://tmp00002.zhaodashen.cn/mp3/chenyixun_003u2qmP0Mp2pW.m4a'
      }).margin({bottom:20})
      Button('播放').onClick(() => this.player.play()).margin({bottom:20})
      Button('暂停').onClick(() => this.player.pause()).margin({bottom:20})
      Button('换一首').onClick(async () => {
        await this.player.reset()
        this.player.url = 'http://tmp00002.zhaodashen.cn/mp3/wangjingwenbupang_0017ZGNs0ISfYi.m4a'
      }).margin({bottom:20})


      Text(`播放进度:${this.currentTime} 、 ${this.duration}`).fontSize(20)
      Text(DateUtil.m2s(this.currentTime)).fontSize(20)
      Slider({
        value: this.currentTime,
        min: 0,
        max: this.duration,
        style: SliderStyle.OutSet
      })
        .showTips(true)
        .onChange((value: number, mode: SliderChangeMode) => {
          console.info('value:' + value + 'mode:' + mode.toString())
          if (mode === 2) {
            this.player.seek(value)
          }

        })
      Text(DateUtil.m2s(this.duration)).fontSize(20).margin({bottom:50})

      Text('音量🔊').fontSize(20)
      Slider({
        value: 100,
        min: 0,
        max: 100,
        style: SliderStyle.OutSet
      })
        .showTips(true)
        .onChange((value: number, mode: SliderChangeMode) => {
          console.info('value:' + value + 'mode:' + mode.toString())
          // this.player.setVolume(0~1范围)
          this.player.setVolume(value/100)
        })


      Text(this.currentLrc).fontSize(30)
    }.padding(50)
  }
}

鸿蒙开发者班级

相关推荐
HMS Core5 小时前
【FAQ】HarmonyOS SDK 闭源开放能力 — Share Kit
华为·harmonyos
昼-枕7 小时前
鸿蒙Flutter实战:构建智能健身教练应用
flutter·华为·harmonyos
昼-枕7 小时前
鸿蒙与 Flutter 的融合探索:跨平台开发的新可能
flutter·华为·harmonyos
特立独行的猫a7 小时前
鸿蒙PC三方库移植:zlib数据压缩库的适配实践
华为·harmonyos·移植·zlib·鸿蒙pc
AirDroid_cn7 小时前
鸿蒙NEXT:平板作为扩展屏时,触摸延迟如何优化?
华为·电脑·harmonyos
wtrees_松阳8 小时前
【弦绝九章】HarmonyOS异步心法:asynchronous插件详解
华为·harmonyos
HarmonyOS_SDK8 小时前
智能填充隐藏功能——自动补全地址表单所在地区
harmonyos
不老刘9 小时前
Sherpa-onnx 离线 TTS 集成解决 openharmony 下语音播报完整方案
harmonyos·鸿蒙·tts·sherpa
音浪豆豆_Rachel9 小时前
Flutter跨平台通信的实战演练:复杂数据结构与单元测试在鸿蒙生态中的完美实现
数据结构·flutter·单元测试·harmonyos