uniapp音频播放方法的使用说明

本文详细介绍了如何在uniapp中实现音频播放控制,包括暂停、继续、切换歌曲、列表播放模式(单曲循环、列表循环、随机播放)以及获取和显示音频时长。方法涉及使用`uni.createInnerAudioContext`和封装的音频播放方法,确保在不同场景下的音频播放逻辑。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

uniapp音频播放方法的使用说明

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

设计思路:

1、音频播放可以暂停,继续
2、播放完成可以继续播放下一条
3、手动切歌上一曲、下一曲
4、列表选择想听的音频
5、顺序播放,单曲循环,随机播放

需要注意的地方:

1、音频开始播放签需要先去获取音频的总时长(在没有音频总时长的情况下)然后再播放音频,这里需要等待音频总时长获取成功后再执行音频播放的函数,如果接口返回音频列表,建议把音频总时长一起返回。两个地方:
切歌换曲函数audio.vue

async changeMusic(witch) {
    audioRecorder.playStop();
    this.currentTime = 0
    switch (this.playType) {
        case 1:
            break;
        case 2:
            //witch:1下一曲;0上一曲
            if (witch == 1) {
                //已经是最后一首歌的情况,在往下一曲就是第一首歌
                this.currentIndex + 1 == this.musicList.length ? this.currentIndex = 0 : ++this
                    .currentIndex
            } else {
                //已经是第一首歌的情况,在往上一曲就是最后一首歌
                this.currentIndex == 0 ? this.currentIndex = this.musicList.length - 1 : --this
                    .currentIndex
            }
            break;
        default:
            let randomNumber = this.getRandomInt(0, this.musicList.length - 1);
            this.currentIndex = randomNumber
    }
    await this.preparation();
    this.startPlay();
},

选择想要播放的音频audio.vue

async cutSong(index) {
    audioRecorder.playStop();
    this.currentIndex = index
    await this.preparation();
    this.startPlay();
    this.isList = false
},

准备要播放的音频信息,主要是为了获取音频的总时长audio.vue

async preparation() {
    this.playObj = this.musicList[this.currentIndex]
    await audioRecorder.getDurationTwo(this.playObj).then(res => {
        this.fullDuration = res.duration
    })
},

2、音频开始播放和继续播放使用的是同一个方法函数,只需要设置音频开始播放的时间位置即可,所以调用音频播放的方法时需要把音频路径和开始播放的时间一起传
调用播放音频方法audio.vue

audioRecorder.playVoiceTwo(this.playObj.path, this.currentTime).then(res => {})

封装的音频播放方法methodfile.js

// 音频播放,用于页面只有一条语音的情况
export async function playVoiceTwo(voicePath, playTime) {
	return new Promise(resolve => {
		// 能多次播放的情况:uni.createInnerAudioContext需要重新获取
		innerAudioContext = uni.createInnerAudioContext();
		innerAudioContext.autoplay = true;
		// 音频路径
		innerAudioContext.src = voicePath;
		// 开始播放的位置
		innerAudioContext.startTime = playTime
		//播放音量
		innerAudioContext.volume = profile.volume
		innerAudioContext.play();
		this.TimeUpdate()
	});
}

封装的音频播放方法中// 能多次播放的情况:uni.createInnerAudioContext需要重新获取
innerAudioContext = uni.createInnerAudioContext();
用于音频临时路径能够多次播放

3、音频暂停时需要存储音频暂停的位置时长,方便继续播放时传值。建议把暂停时长传出到页面,方便设置
音频播放暂停methodfile.js

export function playPause() {
	return new Promise((resolve, reject) => {
		innerAudioContext.pause();
		resolve(currentTime)
	})
}

4、音频销毁实例,在页面销毁时调用,用于释放空间。该代码中未使用到音频实例销毁。

附上源码:播放部分和列表显示部分写在同一个页面

vue文件:audio.vue

<template>
	<view>
		<view v-show="!isList">
			<!-- 音频名称 -->
			<view class="music-title">
				{{playObj.name}}
			</view>
			<!-- 音频封面 -->
			<view class="music-cover row-layout">
				<image src="/static/image/logo.png" :class="playing?'cover-image':''"></image>
			</view>
			<!-- 音频操作按钮 -->
			<view class="page-top row-layout">
				<view class="operate-btn" @click="changeMusic(0)">
					<image src="/static/image/gf-previous.png"></image>
					<view class="btn_text">上一曲</view>
				</view>
				<view class="operate-btn" v-show="!playing" @click="startPlay()">
					<image src="/static/image/gf-play.png"></image>
					<view class="btn_text">播放</view>
				</view>
				<view class="operate-btn" v-show="playing" @click="pausePlay()">
					<image src="/static/image/gf-pause.png"></image>
					<view class="btn_text">暂停</view>
				</view>
				<view class="operate-btn" @click="changeMusic(1)">
					<image src="/static/image/gf-next.png"></image>
					<view class="btn_text">下一曲</view>
				</view>
			</view>
			<!-- 音频播放模式 -->
			<view class="page-footer row-layout">
				<view class="other-btn" v-show="playType==3" @click="changeType()">
					<image src="/static/image/random.png"></image>
				</view>
				<view class="other-btn" v-show="playType==2" @click="changeType()">
					<image src="/static/image/listloop.png"></image>
				</view>
				<view class="other-btn" v-show="playType==1" @click="changeType()">
					<image src="/static/image/singlecycle.png"></image>
				</view>
				<view class="other-btn" @click="isList = true">
					<image src="/static/image/playlistMusic.png"></image>
				</view>
			</view>
			<view class="divider-line"></view>
		</view>
		<!-- 音频列表 -->
		<view class="pages-list" v-show="isList">
			<!-- 可滚动区域 -->
			<scroll-view :scroll-top="scrollTop" scroll-y="true" @scroll="scroll" class="scroll-Y">
				<view>
					<view class="list-item row-layout" v-for="(item,index) in musicList" :key="index"
						@click="cutSong(index)">
						<!-- 序号 -->
						<view>{{index>=9?(index+1):'0'+(index+1)}}</view>
						<image src="/static/image/logo.png"></image>
						<view>{{item.name}}</view>
					</view>
				</view>
			</scroll-view>
		</view>
	</view>
</template>

<script>
	import * as audioRecorder from '@/audioRecorder/methodfile.js'; //音频封装的方法文件
	export default {
		props: {
			musicList: {
				type: Array,
				default: []
			}
		},
		data() {
			return {
				playing: false, //播放状态
				playObj: {}, //正在播放的信息
				currentTime: 0, //播放开始位置时间
				currentIndex: 0, //正在播放的索引
				fullDuration: 0, //音频总时长
				playType: 2, //播放模式默认2:列表循环播放,1:单曲循环,3:随机播放
				isList: false, //是否显示音频列表
				scrollTop: 0, //滚动区域的顶部距离
				old: {
					scrollTop: 0
				},
			}
		},
		mounted() {
			this.preparation();
		},
		methods: {
			//准备要播放的音频信息,主要是为了获取音频的总时长
			async preparation() {
				this.playObj = this.musicList[this.currentIndex]
				await audioRecorder.getDurationTwo(this.playObj).then(res => {
					this.fullDuration = res.duration
				})
			},
			//开始播放
			startPlay() {
				this.playing = true
				audioRecorder.playVoiceTwo(this.playObj.path, this.currentTime).then(res => {})
				setTimeout(() => {
					this.changeMusic(1);
				}, this.fullDuration * 1000)
			},
			//暂停播放
			pausePlay() {
				this.playing = false
				audioRecorder.playPause().then(res => {
					this.currentTime = res
				})
			},
			//切歌换曲
			async changeMusic(witch) {
				audioRecorder.playStop();
				this.currentTime = 0
				switch (this.playType) {
					case 1:
						break;
					case 2:
						//witch:1下一曲;0上一曲
						if (witch == 1) {
							//已经是最后一首歌的情况,在往下一曲就是第一首歌
							this.currentIndex + 1 == this.musicList.length ? this.currentIndex = 0 : ++this
								.currentIndex
						} else {
							//已经是第一首歌的情况,在往上一曲就是最后一首歌
							this.currentIndex == 0 ? this.currentIndex = this.musicList.length - 1 : --this
								.currentIndex
						}
						break;
					default:
						let randomNumber = this.getRandomInt(0, this.musicList.length - 1);
						this.currentIndex = randomNumber
				}
				await this.preparation();
				this.startPlay();
			},
			// 生成随机数,用于随机播放
			getRandomInt(min, max) {
				let minnum = Math.ceil(min);
				let maxnum = Math.floor(max);
				return Math.floor(Math.random() * (maxnum - minnum + 1)) + minnum;
			},
			//切换播放方式
			changeType() {
				this.playType == 3 ? this.playType = 1 : ++this.playType
			},
			// 选择想要播放的音频
			async cutSong(index) {
				audioRecorder.playStop();
				this.currentIndex = index
				await this.preparation();
				this.startPlay();
				this.isList = false
			},
			// 滚动
			scroll: function(e) {
				this.old.scrollTop = e.detail.scrollTop
			},
		}
	}
</script>

<style lang="scss" scoped>
	.music-title {
		font-size: 38rpx;
		font-weight: 600;
		text-align: center;
	}

	.music-cover {
		margin-top: 12%;
		justify-content: center;

		image {
			width: 170rpx;
			/* 设置图像宽度,根据需要调整 */
			height: 170rpx;
			/* 设置图像高度,根据需要调整 */
			border-radius: 50%;
		}

		.cover-image {
			animation: rotateAnimation 3s linear infinite;
			/* 设置动画:名称 时间 函数 迭代次数 */
		}

		/* 定义旋转动画关键帧 */
		@keyframes rotateAnimation {
			from {
				transform: rotate(0deg);
			}

			to {
				transform: rotate(360deg);
			}
		}
	}

	.page-top {
		margin-top: 16%;
		justify-content: space-between;

		.operate-btn {
			text-align: center;

			image {
				width: 66rpx;
				height: 66rpx;
			}

			.btn_text {
				font-size: 30rpx;
			}
		}
	}

	.page-footer {
		margin-top: 16%;
		justify-content: flex-end;

		.other-btn {
			image {
				width: 55rpx;
				height: 55rpx;
				margin: 0 40rpx;
			}
		}
	}

	.divider-line {
		position: absolute;
		top: 50%;
		left: 0;
		width: 100vw;
		height: 6rpx;
		background: gray;
	}

	.pages-list {
		.scroll-Y {}

		.list-item {
			padding-bottom: 30rpx;
			margin-bottom: 30rpx;
			border-bottom: 2rpx solid #ededed;

			image {
				width: 66rpx;
				height: 66rpx;
				margin: 0 38rpx;
			}
		}
	}
</style>

方法文件:methodfile.js

import profile from './profile.js';
// 全局定义音频
let innerAudioContext = uni.createInnerAudioContext();
innerAudioContext.autoplay = true;
let currentTime = 0
/**
 * 音频播放、暂停、继续、结束方法
 */
// 音频播放,用于页面只有一条语音的情况
export async function playVoiceTwo(voicePath, playTime) {
	return new Promise(resolve => {
		// 能多次播放的情况:uni.createInnerAudioContext需要重新获取
		innerAudioContext = uni.createInnerAudioContext();
		innerAudioContext.autoplay = true;
		// 音频路径
		innerAudioContext.src = voicePath;
		// 开始播放的位置
		innerAudioContext.startTime = playTime
		//播放音量
		innerAudioContext.volume = profile.volume
		innerAudioContext.play();
		this.TimeUpdate()
	});
}
//计算音频时长,用于页面只有一条语音并要展示语音时长的情况
export async function getDurationTwo(item) {
	return new Promise(resolve => {
		const audioContext = uni.createInnerAudioContext();
		// 设置音频的路径
		audioContext.src = item.path;
		// 监听音频加载完成事件
		audioContext.onCanplay(() => {
			// 获取音频的时长(单位:秒)
			const duration = Math.round(audioContext.duration);
			const min = Math.floor(duration / 60); // 获取分钟数
			const second = (duration % 60) < 10 ? '0' + (duration % 60) : (duration % 60);
			const times = min + ':' + second
			// 将时长打印到控制台或进行其他操作
			Object.assign(item, {
				duration: audioContext.duration,
				seconds: times
			});
			// 计算完时长后销毁创建的音频实例
			audioContext.destroy();
			resolve(item); // 异步操作完成后调用resolve,标识异步操作完成
		});
	});
}
// 音频播放进度更新事件,主要是获取播放的位置,继续播放时连着暂停的位置继续往下播放
export function TimeUpdate() {
	// 监听音频播放进度变化事件
	innerAudioContext.onTimeUpdate(() => {
		// 获取当前音频播放的时间
		currentTime = innerAudioContext.currentTime;
	});
}
// 音频播放暂停
export function playPause() {
	return new Promise((resolve, reject) => {
		innerAudioContext.pause();
		resolve(currentTime)
	})
}
// 音频播放停止
export function playStop() {
	return new Promise((resolve, reject) => {
		// 确保recorderManager对象被成功初始化后再调用stop方法
		if (innerAudioContext) {
			innerAudioContext.stop();
			resolve()
		} else {
			reject('innerAudioContext未成功初始化');
		}
	})
}
// 音频实例销毁
export function playDestroy() {
	innerAudioContext.destroy();
}

配置文件:profile.js

let DURATION = 180000 //录音时长,毫秒
let VOLUME = 0.2  //音频播放音量0~1

const profile = {
	duration: DURATION,
	volume: VOLUME
};

export default profile
<think>好的,我需要回答用户关于在UniApp中实现音频文件播放的问题,特别是使用API的示例教程。首先,我需要回顾用户提供的引用内容,看看是否有相关的信息。引用[1]提到了uni.getBackgroundAudioManager(),这个API显然是用于背景音频播放的,适合音乐播放器之类的应用。引用[2]和[3]则更多涉及文件预览和媒体文件管理,但可能也包含一些有用的信息。 用户想要知道如何播放音频文件,可能需要两种方式:普通音频播放和后台播放。根据引用[1],uni.getBackgroundAudioManager()是处理后台播放的,而普通播放可能使用innerAudioContext。我需要确认UniApp的文档是否支持这两种方式,并给出示例代码。 接下来,我应该分步骤说明如何实现这两种播放方式。对于普通播放使用uni.createInnerAudioContext(),设置src,然后调用play()。对于后台播放使用uni.getBackgroundAudioManager(),同样设置src和title,然后播放。需要注意两者的区别,比如后台播放需要设置title,且在退出页面时仍能播放。 另外,用户可能需要处理音频源的问题,比如本地文件还是远程URL。引用[2]提到在线下载并预览文件,所以可能需要从网络获取音频文件,但播放API应该支持远程URL。同时,引用[3]中的MediaStore可能涉及如何获取本地文件路径,不过UniApp通常使用相对路径或网络路径,可能需要使用uni.downloadFile下载远程文件到本地临时路径后再播放。 还需要考虑权限问题,比如在manifest.json中配置音频播放权限,特别是安卓平台。此外,测试时要注意真机调试,因为模拟器可能不支持某些功能。 最后,生成相关问题,帮助用户进一步了解音频播放的其他方面,比如控制播放进度、事件监听、UI设计等。</think>### UniApp音频文件播放实现方法UniApp中实现音频播放功能,主要涉及两种场景:普通音频播放和后台持续播放。以下是具体实现方法和示例代码: --- #### 一、普通音频播放(适合短音频使用`uni.createInnerAudioContext()` API实现基础播放功能,适合短音频且不需要后台持续播放的场景。 **实现步骤:** 1. 创建音频实例 2. 配置音频源与参数 3. 添加播放控制逻辑 ```javascript // 创建音频实例 const innerAudioContext = uni.createInnerAudioContext(); // 配置音频源(支持本地和远程路径) innerAudioContext.src = 'https://example.com/audio.mp3'; // 监听播放事件 innerAudioContext.onPlay(() => { console.log('开始播放'); }); // 播放控制 function playAudio() { innerAudioContext.play(); } function pauseAudio() { innerAudioContext.pause(); } // 销毁实例(页面卸载时调用) onUnload(() => { innerAudioContext.destroy(); }); ``` --- #### 二、后台音频播放(长音频场景) 通过`uni.getBackgroundAudioManager()`实现后台播放功能,支持锁屏状态持续播放[^1]。 ```javascript const bgAudioManager = uni.getBackgroundAudioManager(); // 必须设置title属性(安卓平台要求) bgAudioManager.title = '音频标题'; bgAudioManager.singer = '创作者'; bgAudioManager.coverImgUrl = 'https://example.com/cover.jpg'; // 设置音频源(支持本地和网络路径) bgAudioManager.src = '/static/audio.mp3'; // 播放控制 function startBackgroundPlay() { bgAudioManager.play(); } function stopBackgroundPlay() { bgAudioManager.stop(); // 停止后会清空src } ``` --- #### 三、关键注意事项 1. **音频源类型** - 网络地址需配置域名白名单(manifest.json中设置) - 本地文件建议放在`static`目录下 2. **平台差异** - iOS需在manifest.json中勾选`audio`权限 - 安卓需添加`<uses-permission android:name="android.permission.WAKE_LOCK"/>` 3. **事件监听** 建议监听`onTimeUpdate`更新进度条,监听`onError`处理异常 ```javascript bgAudioManager.onError((res) => { console.log('播放错误:', res.errMsg); }); ``` --- #### 四、完整功能扩展建议 1. 实现进度条控制 ```javascript bgAudioManager.onTimeUpdate(() => { const progress = bgAudioManager.currentTime / bgAudioManager.duration; }); ``` 2. 添加播放列表管理 可通过数组存储多个音频地址,配合索引切换 3. 状态持久化 使用`uni.setStorage`保存播放进度 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值