uniapp背景音频管理器-backgroundAudioManager

439 阅读2分钟

最近公司在小程序的项目中应用到了该功能(官网地址),过程中也是出现一些问题,特此和前端小伙伴分享一波。

首先,创建一个pinia的js文件(官网描述-获取全局唯一的背景音频管理器)

状态部分

  const audioList = ref([]) //播放列表
  const currentIndex = ref(0) //播放索引
  const isPlaying = ref(false) // 是否播放
  const currentSong = ref(null) //当前播放歌曲
  const currentTime = ref(0) //当前播放时间

初始化部分

 const initAudioManager = () => {
    backgroundAudioManager = uni.getBackgroundAudioManager()
  
    backgroundAudioManager.onPlay(() => {
      isPlaying.value = true;
    });
  
    backgroundAudioManager.onPause(() => {
    // 暂停
	console.log('pause')
      isPlaying.value = false;
    });
  
    backgroundAudioManager.onStop(() => {
       // 停止播放 (在实机的微信小程序里点击缩放的背景音频的 X 关闭)
      isPlaying.value = false;
      currentSong.value = null;
    });
  
    backgroundAudioManager.onEnded(() => {
       // 当前歌曲结束
      isPlaying.value = false;
      playNext();
    });
  
    backgroundAudioManager.onPrev(() => {
      // 在实机的微信小程序里的背景音频点开进入后点击上一首 (iOS only)
      playPrev();
    });
  
    backgroundAudioManager.onNext(() => {
      // 在实机的微信小程序里的背景音频点开进入后点击下一首 (iOS only)
      playNext();
    });
	backgroundAudioManager.onTimeUpdate(function () {
        //用于页面进度条显示
	  currentTime.value = Math.ceil(backgroundAudioManager.currentTime);
	});
    backgroundAudioManager.onError((res) => {
      console.error("播放错误:", res);
      uni.showToast({
        title: "播放出错",
        icon: "none",
      });
    });
  };

功能部分

//播放
  const playSong = (song, currentTime, rate=1) => {
      //song audioList中的一条数据
      //currentTime 当前播放的时间
      //rate 当前播放的倍率
    if (!song) return;
	if (!song.src) {
		getSongUrl(song, currentTime) //获取url 根据公司情况自行实现
		return
	}
    currentSong.value = song;
    backgroundAudioManager.playbackRate = rate
    backgroundAudioManager.title = song.title;
    backgroundAudioManager.singer = song.artist || "未知歌手";
    backgroundAudioManager.epname = song.album || "未知专辑";
    backgroundAudioManager.coverImgUrl = song.cover || `xxx.png`;
    if(currentTime){
	// startTime实现seek函数效果
    	backgroundAudioManager.startTime = currentTime
    }
        // 背景音频管理器实现切换的关键是给一个新的src
	backgroundAudioManager.src = song.src; //当设置了新的 src 时,会自动开始播放
  };
  
   // 切换播放/暂停
  const togglePlay = (playIndex,innerClickItemId,speed) => {
	  // 当前没播放-直接播放
    if (!currentSong.value) {
      playSong(audioList.value[currentIndex.value], 0, speed);
      return;
    }
	// 当前存在播放 判断点击是否是当前播放的语音 
	  if(不是 -直接播放){ //伪代码-根据公司实际业务情况实现
		// backgroundAudioManager.playbackRate = speed
		playSong(audioList.value[playIndex], 0, speed);
	  } else {
		  if ( 是 - 暂停或取消) {
			  backgroundAudioManager.pause();
		  } else {
			  backgroundAudioManager.play();
		  }
	  }
	currentIndex.value = playIndex
    clickItemId.value = innerClickItemId
  };
  // 上一首
   const playPrev = () => {
    if (currentIndex.value <= 0) {
      currentIndex.value = audioList.value.length - 1;
    } else {
      currentIndex.value--;
    }
    playSong(audioList.value[currentIndex.value]);
  };
  
   // 播放下一首
  const playNext = () => {
    if (currentIndex.value >= audioList.value.length - 1) {
    //列表播放完结束 可以设置currentIndex为0 循环播放
	  backgroundAudioManager.stop();
	  return
    } else {
      currentIndex.value++;
    }
    playSong(audioList.value[currentIndex.value]);
  };

有坑的部分功能

// 跳转到指定时间
 const seek = (time, innerClickItemId, pause) => {
	  const rate = backgroundAudioManager.playbackRate
	  if(!pause) {
		// 停止后设置startTime再重新播放,直接用backgroundAudioManager的seek函数有问题会从头播放
		backgroundAudioManager.stop();
		setTimeout(()=>{
			playSong(audioList.value[currentIndex.value], time, rate)
		},100)
	  }
 }
 // 切换倍率
  const changeSpeed = (rate, pause, innerClickItemId) => {
      // 切换倍率同理,先停止后再初始化
	 const currentTime = backgroundAudioManager.currentTime
	 backgroundAudioManager.stop();
	 if(!pause) {
		 setTimeout(()=>{
			 playSong(audioList.value[currentIndex.value],currentTime, rate)
		 },100)
	 }
	 
 }

第一版实现中是通过直接将后端的get请求作为backgroundAudioManager的src来做的,然后通过每次给get请求的自定义query添加一个字符(如?date=1111,每次后面加1)这样可以不用stop只需暂停pause后再播放就能实现效果,但是这样写又会有问题(在一些机型上请求会报错:该内容因网络或其他原因暂时无法播放)查阅网上一些解决方案试了下不能解决该问题,后来改用这版