《悬浮窗效果》三、Interface_AVPlayer使用指南
HarmonyOS Interface (AVPlayer) 使用指南从入门到实战摘要AVPlayer是 HarmonyOS 媒体播放的核心接口支持音频和视频的端到端播放。本文基于 HarmonyOS NEXT开发实践系统讲解AVPlayer的状态机模型、完整播放流程、资源加载方式和控制方法帮助开发者快速实现音频播放功能。效果一、AVPlayer 概述AVPlayer位于kit.MediaKit模块的media命名空间下是 HarmonyOS 推荐的媒体播放组件。相比旧版PlayerAVPlayer提供了更完善的状态机管理和更丰富的功能支持。1.1 导入方式import{media}fromkit.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/urlprepare()preparedprepare成功后play()、seek()、setPlaybackSpeed()playingplay成功后pause()、stop()、seek()pausedpause成功后play()、stop()、seek()completed播放结束stop()、seek()stoppedstop后prepare()循环播放releasedrelease后不可再操作实例已销毁error操作出错reset()回到 idle三、完整播放流程3.1 创建 AVPlayer 实例letavPlayer:media.AVPlayerawaitmedia.createAVPlayer();3.2 注册回调函数必须在设置播放源之前注册回调否则可能错过状态变化通知。// 状态机变化回调最核心的回调avPlayer.on(stateChange,async(state:string,reason:media.StateChangeReason){switch(state){caseidle:// idle状态reset后触发可release释放资源avPlayer.release();break;caseinitialized:// initialized状态设置播放源后触发avPlayer.prepare();// 准备播放break;caseprepared:// prepared状态准备完成可以播放avPlayer.play();// 开始播放break;caseplaying:// 正在播放break;casepaused:// 已暂停break;casecompleted:// 播放完成avPlayer.stop();// 停止播放break;casestopped:// 已停止可重新prepare循环播放avPlayer.prepare();break;casereleased:// 已释放资源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}fromkit.AbilityKit;asyncfunctionplayRawfileAudio(ctx:Context){letavPlayerawaitmedia.createAVPlayer();// 注册回调省略见3.2registerCallbacks(avPlayer);// 获取rawfile资源letcontextctxascommon.UIAbilityContext;letfileDescriptorawaitcontext.resourceManager.getRawFd(audio.mp3);letavFileDescriptor:media.AVFileDescriptor{fd:fileDescriptor.fd,offset:fileDescriptor.offset,length:fileDescriptor.length};// 设置播放源 → 触发 initialized 状态avPlayer.fdSrcavFileDescriptor;}方式二播放网络URLasyncfunctionplayUrlAudio(){letavPlayerawaitmedia.createAVPlayer();// 注册回调省略见3.2registerCallbacks(avPlayer);// 设置URL → 触发 initialized 状态avPlayer.urlhttps://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}fromkit.MediaKit;import{common}fromkit.AbilityKit;import{audio}fromkit.AudioKit;import{hilog}fromkit.PerformanceAnalysisKit;exportclassAudioPlayerService{privateavPlayer?:media.AVPlayerundefined;privatecurrentState:string;publicstaticinstance:AudioPlayerServicenewAudioPlayerService();/** * 注册AVPlayer回调函数 */privateregisterCallbacks(avPlayer:media.AVPlayer):void{// 状态机变化回调avPlayer.on(stateChange,async(state:string){hilog.info(0x0000,AudioPlayer,状态变化: %{public}s,state);this.currentStatestate;switch(state){caseidle:// reset后到达idle释放资源avPlayer.release();break;caseinitialized:// 设置播放源后到达配置音频参数并准备avPlayer.audioRendererInfo{usage:audio.StreamUsage.STREAM_USAGE_MUSIC,rendererFlags:0};avPlayer.prepare();break;caseprepared:// 准备完成开始播放avPlayer.play();break;caseplaying:hilog.info(0x0000,AudioPlayer,正在播放);break;casepaused:hilog.info(0x0000,AudioPlayer,已暂停);break;casecompleted:// 播放完成停止后可重新prepare实现循环avPlayer.stop();break;casestopped:// 停止后重新准备实现循环播放avPlayer.prepare();break;casereleased: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):Promisevoid{letavPlayerawaitmedia.createAVPlayer();this.registerCallbacks(avPlayer);letcontextctxascommon.UIAbilityContext;letfileDescriptorawaitcontext.resourceManager.getRawFd(resourceName);letavFileDescriptor:media.AVFileDescriptor{fd:fileDescriptor.fd,offset:fileDescriptor.offset,length:fileDescriptor.length};avPlayer.fdSrcavFileDescriptor;this.avPlayeravPlayer;}/** * 切换播放/暂停 */togglePlayPause(ctx:Context,resourceName:string):void{if(this.avPlayerundefined){// 首次播放创建播放器this.playFromRawfile(ctx,resourceName);}elseif(this.currentStateplaying){this.avPlayer.pause();}else{this.avPlayer.play();}}/** * 获取当前状态 */getState():string{returnthis.currentState;}}4.2 在组件中使用import{AudioPlayerService}from../utils/AudioPlayerService;EntryComponentstruct AudioPage{LocalisPlaying:booleanfalse;privatectx?:Contextthis.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.0avPlayer.volume0.8;// 设置播放速度0.5x ~ 2.0xavPlayer.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(statecompleted){avPlayer.stop();// 播放完成后停止// → stopped 状态}if(statestopped){avPlayer.prepare();// 停止后重新准备// → prepared 状态 → play() 自动播放}});6.5 单例模式管理推荐使用单例模式管理 AVPlayer 实例避免创建多个播放器exportclassAudioPlayerService{publicstaticinstance:AudioPlayerServicenewAudioPlayerService();privateavPlayer?:media.AVPlayer;// 确保全局只有一个播放器实例}七、AVPlayer 回调事件速查表事件名说明回调参数stateChange状态机变化(state: string, reason: StateChangeReason)seekDoneseek操作完成(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 悬浮窗开发避坑指南