《悬浮窗效果》三、Interface_AVPlayer使用指南
HarmonyOS Interface (AVPlayer) 使用指南:从入门到实战
摘要:
AVPlayer是 HarmonyOS 媒体播放的核心接口,支持音频和视频的端到端播放。本文基于 HarmonyOS NEXT开发实践,系统讲解AVPlayer的状态机模型、完整播放流程、资源加载方式和控制方法,帮助开发者快速实现音频播放功能。
效果
一、AVPlayer 概述
AVPlayer位于@kit.MediaKit模块的media命名空间下,是 HarmonyOS 推荐的媒体播放组件。相比旧版Player,AVPlayer提供了更完善的状态机管理和更丰富的功能支持。
1.1 导入方式
import{media}from'@kit.MediaKit';1.2 支持的播放源
| 播放源类型 | 说明 | 设置方式 |
|---|---|---|
| fdSrc | 本地文件描述符(rawfile资源) | avPlayer.fdSrc = { fd, offset, length } |
| url | 网络URL地址 | avPlayer.url = 'https://...' |
| dataSrc | 内存数据流 | avPlayer.dataSrc = dataSrcDescriptor |
二、状态机模型
AVPlayer采用有限状态机设计,所有操作必须在正确的状态下调用。理解状态机是使用AVPlayer的关键。
2.1 状态流转图
┌──────────────────────────────────────────────┐ │ │ ▼ │ [idle] ──setPlaySource──▶ [initialized] ──prepare──▶ [prepared] │ ▲ │ │ │ ▼ │ │ reset() [released] ◄──release()── [stopped] ◄──play()──▶[playing] │ ▲ ▲ │ │ │ │ ▼ │ │ stop() [paused] │ │ │ │ │ │ │ play()│ │ │ │ │ │ │ ▼ │ │ │ [completed]───────┘ │ │ │ │ │ │ (循环播放) │ │ ▼ │ └────────────────────── [prepared] │ └── error ──▶ [error] ──reset()──▶ [idle]2.2 各状态说明
| 状态 | 触发条件 | 可执行操作 |
|---|---|---|
idle | 初始状态 / reset后 / error后 | release() |
initialized | 设置播放源后(fdSrc/url) | prepare() |
prepared | prepare成功后 | play()、seek()、setPlaybackSpeed() |
playing | play成功后 | pause()、stop()、seek() |
paused | pause成功后 | play()、stop()、seek() |
completed | 播放结束 | stop()、seek() |
stopped | stop后 | prepare()(循环播放) |
released | release后 | 不可再操作,实例已销毁 |
error | 操作出错 | reset()回到 idle |
三、完整播放流程
3.1 创建 AVPlayer 实例
letavPlayer:media.AVPlayer=awaitmedia.createAVPlayer();3.2 注册回调函数
必须在设置播放源之前注册回调,否则可能错过状态变化通知。
// 状态机变化回调(最核心的回调)avPlayer.on('stateChange',async(state:string,reason:media.StateChangeReason)=>{switch(state){case'idle':// idle状态:reset后触发,可release释放资源avPlayer.release();break;case'initialized':// initialized状态:设置播放源后触发avPlayer.prepare();// 准备播放break;case'prepared':// prepared状态:准备完成,可以播放avPlayer.play();// 开始播放break;case'playing':// 正在播放break;case'paused':// 已暂停break;case'completed':// 播放完成avPlayer.stop();// 停止播放break;case'stopped':// 已停止,可重新prepare循环播放avPlayer.prepare();break;case'released':// 已释放资源break;}});// seek操作完成回调avPlayer.on('seekDone',(seekDoneTime:number)=>{console.info(`seek完成,当前位置:${seekDoneTime}ms`);});// 错误回调avPlayer.on('error',(err)=>{console.error(`播放错误: code=${err.code}, message=${err.message}`);avPlayer.reset();// 出错后调用reset回到idle状态});3.3 设置播放源
方式一:播放 rawfile 资源(推荐用于本地音频)
import{common}from'@kit.AbilityKit';asyncfunctionplayRawfileAudio(ctx:Context){letavPlayer=awaitmedia.createAVPlayer();// 注册回调(省略,见3.2)registerCallbacks(avPlayer);// 获取rawfile资源letcontext=ctxascommon.UIAbilityContext;letfileDescriptor=awaitcontext.resourceManager.getRawFd('audio.mp3');letavFileDescriptor:media.AVFileDescriptor={fd:fileDescriptor.fd,offset:fileDescriptor.offset,length:fileDescriptor.length};// 设置播放源 → 触发 initialized 状态avPlayer.fdSrc=avFileDescriptor;}方式二:播放网络URL
asyncfunctionplayUrlAudio(){letavPlayer=awaitmedia.createAVPlayer();// 注册回调(省略,见3.2)registerCallbacks(avPlayer);// 设置URL → 触发 initialized 状态avPlayer.url='https://example.com/audio.mp3';}3.4 播放控制
// 播放avPlayer.play();// 暂停avPlayer.pause();// 停止avPlayer.stop();// 跳转(单位:毫秒)avPlayer.seek(30000);// 跳转到30秒// 释放资源avPlayer.release();// 重置(回到idle状态)avPlayer.reset();四、完整示例:音频播放服务
以下示例封装了一个完整的音频播放服务类,支持播放/暂停切换、错误处理和资源管理。
4.1 音频播放服务类
import{media}from'@kit.MediaKit';import{common}from'@kit.AbilityKit';import{audio}from'@kit.AudioKit';import{hilog}from'@kit.PerformanceAnalysisKit';exportclassAudioPlayerService{privateavPlayer?:media.AVPlayer=undefined;privatecurrentState:string='';publicstaticinstance:AudioPlayerService=newAudioPlayerService();/** * 注册AVPlayer回调函数 */privateregisterCallbacks(avPlayer:media.AVPlayer):void{// 状态机变化回调avPlayer.on('stateChange',async(state:string)=>{hilog.info(0x0000,'AudioPlayer','状态变化: %{public}s',state);this.currentState=state;switch(state){case'idle':// reset后到达idle,释放资源avPlayer.release();break;case'initialized':// 设置播放源后到达,配置音频参数并准备avPlayer.audioRendererInfo={usage:audio.StreamUsage.STREAM_USAGE_MUSIC,rendererFlags:0};avPlayer.prepare();break;case'prepared':// 准备完成,开始播放avPlayer.play();break;case'playing':hilog.info(0x0000,'AudioPlayer','正在播放');break;case'paused':hilog.info(0x0000,'AudioPlayer','已暂停');break;case'completed':// 播放完成,停止后可重新prepare实现循环avPlayer.stop();break;case'stopped':// 停止后重新准备,实现循环播放avPlayer.prepare();break;case'released':hilog.info(0x0000,'AudioPlayer','资源已释放');break;}});// seek完成回调avPlayer.on('seekDone',(seekDoneTime:number)=>{hilog.info(0x0000,'AudioPlayer','seek完成: %{public}d',seekDoneTime);});// 错误回调avPlayer.on('error',(err)=>{hilog.error(0x0000,'AudioPlayer','播放错误: code=%{public}d, message=%{public}s',err.code,err.message);avPlayer.reset();});}/** * 播放rawfile中的音频资源 */asyncplayFromRawfile(ctx:Context,resourceName:string):Promise<void>{letavPlayer=awaitmedia.createAVPlayer();this.registerCallbacks(avPlayer);letcontext=ctxascommon.UIAbilityContext;letfileDescriptor=awaitcontext.resourceManager.getRawFd(resourceName);letavFileDescriptor:media.AVFileDescriptor={fd:fileDescriptor.fd,offset:fileDescriptor.offset,length:fileDescriptor.length};avPlayer.fdSrc=avFileDescriptor;this.avPlayer=avPlayer;}/** * 切换播放/暂停 */togglePlayPause(ctx:Context,resourceName:string):void{if(this.avPlayer===undefined){// 首次播放,创建播放器this.playFromRawfile(ctx,resourceName);}elseif(this.currentState==='playing'){this.avPlayer.pause();}else{this.avPlayer.play();}}/** * 获取当前状态 */getState():string{returnthis.currentState;}}4.2 在组件中使用
import{AudioPlayerService}from'../utils/AudioPlayerService';@Entry@Componentstruct AudioPage{@LocalisPlaying:boolean=false;privatectx?:Context=this.getUIContext().getHostContext();build(){Column({space:20}){Text('AVPlayer 音频播放示例').fontSize(20).fontWeight(FontWeight.Bold)Text(this.isPlaying?'正在播放...':'已暂停').fontSize(16).fontColor(this.isPlaying?'#4CAF50':'#999999')Button(this.isPlaying?'暂停':'播放').fontSize(16).onClick(()=>{AudioPlayerService.instance.togglePlayPause(this.ctx!,'sample.wav');this.isPlaying=!this.isPlaying;})}.width('100%').height('100%').justifyContent(FlexAlign.Center)}}五、音频渲染参数配置
5.1 audioRendererInfo
在initialized状态下设置音频渲染参数:
avPlayer.audioRendererInfo={// 音频流使用类型usage:audio.StreamUsage.STREAM_USAGE_MUSIC,// 音乐// rendererFlags: 0 // 音频渲染器标志};常用 StreamUsage 类型:
| 类型 | 说明 |
|---|---|
STREAM_USAGE_MUSIC | 音乐播放 |
STREAM_USAGE_VOICE_COMMUNICATION | 语音通话 |
STREAM_USAGE_NOTIFICATION | 通知提示音 |
STREAM_USAGE_ALARM | 闹钟 |
STREAM_USAGE_GAME | 游戏音效 |
5.2 其他播放参数
// 设置音量(0.0 ~ 1.0)avPlayer.volume=0.8;// 设置播放速度(0.5x ~ 2.0x)avPlayer.setPlaybackSpeed(1.5);// 设置循环模式(需要手动在completed状态处理)// AVPlayer本身不直接支持循环,需在stateChange回调中实现六、开发要点与最佳实践
6.1 回调注册时机
正确顺序: 1. createAVPlayer() → 创建实例 2. on('stateChange') → 注册状态回调 ★ 必须在设置播放源之前 3. on('error') → 注册错误回调 ★ 必须在设置播放源之前 4. fdSrc / url → 设置播放源(触发状态机流转) 错误顺序: 1. createAVPlayer() 2. fdSrc → ✗ 可能错过 initialized 状态 3. on('stateChange') → ✗ 已来不及接收状态变化6.2 错误处理策略
avPlayer.on('error',(err)=>{// 1. 记录错误日志hilog.error(0x0000,'AVPlayer','错误: %{public}s',JSON.stringify(err));// 2. 调用reset回到idle状态avPlayer.reset();// 3. 在idle状态的stateChange回调中release释放资源});6.3 资源释放
// 正确的资源释放流程avPlayer.stop();// 先停止// → stopped 状态// 在 stateChange 的 idle 回调中:avPlayer.release();// 释放资源// → released 状态,实例不可再使用6.4 循环播放实现
AVPlayer不直接支持循环播放,需要在状态机回调中手动实现:
avPlayer.on('stateChange',async(state:string)=>{if(state==='completed'){avPlayer.stop();// 播放完成后停止// → stopped 状态}if(state==='stopped'){avPlayer.prepare();// 停止后重新准备// → prepared 状态 → play() 自动播放}});6.5 单例模式管理
推荐使用单例模式管理 AVPlayer 实例,避免创建多个播放器:
exportclassAudioPlayerService{publicstaticinstance:AudioPlayerService=newAudioPlayerService();privateavPlayer?:media.AVPlayer;// 确保全局只有一个播放器实例}七、AVPlayer 回调事件速查表
| 事件名 | 说明 | 回调参数 |
|---|---|---|
stateChange | 状态机变化 | (state: string, reason: StateChangeReason) |
seekDone | seek操作完成 | (seekDoneTime: number) |
error | 操作出错 | (err: BusinessError) |
timeUpdate | 播放时间更新 | (time: number) |
durationUpdate | 总时长更新 | (duration: number) |
bufferingUpdate | 缓冲更新 | (infoType: BufferingInfoType, value: number) |
audioInterruptBegin | 音频焦点被抢占开始 | () |
audioInterruptEnd | 音频焦点恢复 | () |
八、总结
AVPlayer是 HarmonyOS 媒体播放的核心组件,掌握以下要点即可应对大部分音频播放场景:
- 状态机模型:理解 idle → initialized → prepared → playing → paused → completed → stopped 的完整流转
- 回调注册:必须在设置播放源之前注册
stateChange和error回调 - 播放源设置:支持 fdSrc(本地资源)、url(网络地址)、dataSrc(内存数据)
- 播放控制:play、pause、stop、seek、release、reset
- 错误处理:error 状态下调用 reset 回到 idle,再 release 释放资源
- 循环播放:在 completed → stop → prepare 链路中实现
相关文档:
- Interface (Window) 使用指南
- Interface (WindowStage) 使用指南
- 简约风格悬浮窗效果案例指南
- ArkTS 悬浮窗开发避坑指南
