发布日期:2023年11月
一、项目概述与技术选型
本教程将带领大家使用UniApp框架开发一个功能完整的跨平台音乐播放器应用。该应用将同时支持iOS、Android、Web及微信小程序平台,展示UniApp在多媒体处理方面的强大能力。
技术栈配置:
- 开发框架:UniApp 3.8+
- 前端语言:Vue.js 3 + Composition API
- 状态管理:Pinia
- UI组件:自定义组件 + uni-ui
- 音频处理:uni.createInnerAudioContext()
二、项目初始化与目录结构
首先使用HBuilderX创建新的UniApp项目,选择Vue3版本模板:
// 项目目录结构
music-player/
├── pages/ // 页面文件
│ ├── index/ // 首页
│ ├── playlist/ // 歌单页
│ └── player/ // 播放页
├── components/ // 自定义组件
│ ├── music-card/ // 音乐卡片
│ ├── progress-bar/ // 进度条
│ └── lyric-view/ // 歌词显示
├── stores/ // 状态管理
│ └── player.js // 播放器状态
├── static/ // 静态资源
│ ├── icons/ // 图标
│ └── images/ // 图片
└── utils/ // 工具函数
└── api.js // 接口封装
三、核心播放器功能实现
1. 音频播放器封装
创建独立的音频播放器管理类,处理播放、暂停、进度控制等核心功能:
class AudioPlayer {
constructor() {
this.innerAudioContext = uni.createInnerAudioContext()
this.setupAudioEvents()
}
setupAudioEvents() {
// 音频加载完成
this.innerAudioContext.onCanplay(() => {
console.log('音频可以播放')
})
// 播放进度更新
this.innerAudioContext.onTimeUpdate(() => {
const currentTime = this.innerAudioContext.currentTime
const duration = this.innerAudioContext.duration
this.updateProgress(currentTime, duration)
})
// 播放结束
this.innerAudioContext.onEnded(() => {
this.playNext()
})
}
play(song) {
if (this.currentSong?.id === song.id) {
this.resume()
return
}
this.currentSong = song
this.innerAudioContext.src = song.url
this.innerAudioContext.play()
}
pause() {
this.innerAudioContext.pause()
}
seek(position) {
this.innerAudioContext.seek(position)
}
}
2. 播放器状态管理
使用Pinia管理全局播放状态:
import { defineStore } from 'pinia'
export const usePlayerStore = defineStore('player', {
state: () => ({
currentSong: null,
playlist: [],
isPlaying: false,
currentTime: 0,
duration: 0,
playMode: 'sequence' // sequence, loop, random
}),
actions: {
setPlaylist(songs) {
this.playlist = songs
},
playSong(song) {
this.currentSong = song
this.isPlaying = true
// 调用音频播放器实例
audioPlayer.play(song)
},
togglePlay() {
this.isPlaying = !this.isPlaying
if (this.isPlaying) {
audioPlayer.resume()
} else {
audioPlayer.pause()
}
}
},
getters: {
progress: (state) => {
return state.duration > 0 ? (state.currentTime / state.duration) * 100 : 0
}
}
})
四、播放界面UI实现
1. 播放页布局
创建沉浸式播放页面,包含唱片旋转动画和歌词同步显示:
<template>
<view class="player-container">
<view class="background" :style="backgroundStyle"></view>
<view class="content">
<!-- 唱片部分 -->
<view class="disc-section">
<view class="disc" :class="{ rotating: isPlaying }">
<image class="album-cover" :src="currentSong.cover" mode="aspectFill"></image>
</view>
</view>
<!-- 歌曲信息 -->
<view class="song-info">
<text class="song-name">{{ currentSong.name }}</text>
<text class="artist">{{ currentSong.artist }}</text>
</view>
<!-- 进度条 -->
<progress-bar
:current-time="currentTime"
:duration="duration"
@seek="onSeek">
</progress-bar>
<!-- 控制按钮 -->
<view class="control-buttons">
<button @click="changePlayMode" class="mode-btn">
<text>{{ modeIcon }}</text>
</button>
<button @click="playPrev" class="prev-btn">上一首</button>
<button @click="togglePlay" class="play-btn">
{{ isPlaying ? '暂停' : '播放' }}
</button>
<button @click="playNext" class="next-btn">下一首</button>
<button @click="toggleLike" class="like-btn">
{{ isLiked ? '已喜欢' : '喜欢' }}
</button>
</view>
</view>
</view>
</template>
<script setup>
import { computed } from 'vue'
import { usePlayerStore } from '@/stores/player'
const playerStore = usePlayerStore()
const backgroundStyle = computed(() => {
return {
backgroundImage: `url(${playerStore.currentSong?.cover})`,
filter: 'blur(20px) brightness(0.6)'
}
})
const togglePlay = () => {
playerStore.togglePlay()
}
const onSeek = (position) => {
audioPlayer.seek(position)
}
</script>
2. 自定义进度条组件
实现可交互的进度条,支持拖动调整播放进度:
<template>
<view class="progress-container">
<text class="time-text">{{ formatTime(currentTime) }}</text>
<view
class="progress-bar"
@touchstart="onTouchStart"
@touchmove="onTouchMove"
@touchend="onTouchEnd">
<view class="progress-background"></view>
<view
class="progress-foreground"
:style="{ width: progress + '%' }">
</view>
<view
class="progress-thumb"
:style="{ left: progress + '%' }">
</view>
</view>
<text class="time-text">{{ formatTime(duration) }}</text>
</view>
</template>
<script setup>
import { computed } from 'vue'
const props = defineProps({
currentTime: Number,
duration: Number
})
const emit = defineEmits(['seek'])
const progress = computed(() => {
return props.duration > 0 ? (props.currentTime / props.duration) * 100 : 0
})
const isSeeking = ref(false)
const onTouchStart = (e) => {
isSeeking.value = true
updateProgress(e)
}
const onTouchMove = (e) => {
if (isSeeking.value) {
updateProgress(e)
}
}
const onTouchEnd = () => {
isSeeking.value = false
}
const updateProgress = (e) => {
const query = uni.createSelectorQuery().in(this)
query.select('.progress-bar').boundingClientRect(rect => {
const touchX = e.touches[0].clientX - rect.left
const percentage = Math.max(0, Math.min(100, (touchX / rect.width) * 100))
const newTime = (percentage / 100) * props.duration
emit('seek', newTime)
}).exec()
}
const formatTime = (seconds) => {
const mins = Math.floor(seconds / 60)
const secs = Math.floor(seconds % 60)
return `${mins}:${secs.toString().padStart(2, '0')}`
}
</script>
五、多平台适配与优化
1. 平台条件编译
针对不同平台进行特定优化:
// 平台特定功能处理
function setupPlatformFeatures() {
// #ifdef APP-PLUS
setupAppFeatures()
// #endif
// #ifdef MP-WEIXIN
setupWechatFeatures()
// #endif
// #ifdef H5
setupH5Features()
// #endif
}
function setupAppFeatures() {
// 处理APP端的后台播放
plus.audio.setSessionCategory('playback')
// 锁屏控制
plus.android.importClass('android.media.AudioManager')
const audioManager = plus.android.runtimeMainContext().getSystemService('audio')
audioManager.requestAudioFocus(null, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN)
}
function setupWechatFeatures() {
// 微信小程序背景音频管理
const backgroundAudioManager = wx.getBackgroundAudioManager()
backgroundAudioManager.title = currentSong.name
backgroundAudioManager.singer = currentSong.artist
backgroundAudioManager.coverImgUrl = currentSong.cover
}
2. 性能优化策略
- 图片懒加载:使用uni.lazyLoad组件优化长列表性能
- 音频预加载:提前加载下一首歌曲减少等待时间
- 虚拟列表:歌单列表使用虚拟滚动提升性能
- 缓存策略:本地缓存歌曲信息和用户偏好设置
六、项目部署与发布
1. 多平台打包配置
在manifest.json中配置各平台特定设置:
{
"app-plus": {
"backgroundAudio": {
"title": "音乐播放器",
"singer": "未知艺术家"
},
"permissions": {
"Audio": {
"description": "需要音频播放权限"
}
}
},
"mp-weixin": {
"requiredBackgroundModes": ["audio"],
"permission": {
"scope.record": {
"desc": "需要录音权限用于语音搜索"
}
}
},
"h5": {
"title": "UniApp音乐播放器",
"template": "index.html"
}
}
2. 发布流程
- 测试各平台功能完整性
- 配置应用图标和启动图
- 生成应用打包文件
- 提交到各应用商店或平台审核
七、总结与扩展
通过本教程,我们完整实现了一个跨平台音乐播放器应用,涵盖了UniApp开发的核心技术点:
- 音频API的深度使用和封装
- 复杂状态管理的实现方案
- 自定义组件的开发技巧
- 多平台适配的最佳实践
- 性能优化的具体策略
项目扩展方向:
- 集成音乐搜索和推荐功能
- 添加用户系统和收藏功能
- 实现歌词同步和翻译显示
- 添加音效均衡器和音质选择
- 开发智能播放列表和场景推荐