尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
Flutter/OpenHarmony 三方库适配实战:audioplayers 多播放器
Flutter/OpenHarmony 三方库适配实战audioplayers 多播放器一、项目信息项目内容仓库名称audioplayers仓库地址https://atomgit.com/oh-flutter/audioplayers基于版本audioplayers 6.5.1适配 TAG6.5.1-ohos-1.0.1OHOS 插件包audioplayers_ohos 5.2.1OHOS 原生入口AudioplayersPlugin原生播放器WrappedPlayer MediaPlayerPlayer实例方法通道xyz.luan/audioplayers全局方法通道xyz.luan/audioplayers.globalaudioplayers支持多个播放器实例同时存在公开 API 包括音源设置、播放、暂停、跳转、音量、倍速、事件流和音频上下文。OHOS 适配需要在保留这些语义的同时处理多个AVPlayer、音频焦点、后台任务和资源释放。二、插件架构本次适配采用实例通道与全局通道分离的结构audioplayers Dart | -- xyz.luan/audioplayers | create / setSource / resume / pause / seek / dispose | -- xyz.luan/audioplayers.global | init / setAudioContext / global log / global error | -- xyz.luan/audioplayers.global/events | v AudioplayersPlugin | -- HashMapplayerId, WrappedPlayer | -- 每个播放器独立 EventChannel | -- MediaPlayerPlayer / SoundPoolPlayer | -- ohos.multimedia.media.AVPlayer实例命令通过playerId找到对应播放器全局命令管理默认音频上下文、日志和全局错误。每个播放器拥有独立事件通道多个播放器同时播放时不会互相串流。三、插件声明与初始化audioplayers_ohos/pubspec.yamlname:audioplayers_ohosversion:5.2.1flutter:plugin:implements:audioplayersplatforms:ohos:package:xyz.luan.audioplayerspluginClass:AudioplayersPlugin原生插件在引擎附加时创建通道和 SoundPool 管理器onAttachedToEngine(binding:FlutterPluginBinding):void{this.contextbinding.getApplicationContext();this.binaryMessengerbinding.getBinaryMessenger();this.soundPoolManagernewSoundPoolManager(this);this.methodsnewMethodChannel(this.binaryMessenger,xyz.luan/audioplayers,);this.globalMethodsnewMethodChannel(this.binaryMessenger,xyz.luan/audioplayers.global,);this.globalEventsnewEventHandler(newEventChannel(this.binaryMessenger,xyz.luan/audioplayers.global/events,),);}Ability 分离时暂停所有正在播放的播放器并停止后台长时任务引擎销毁时释放所有实例、SoundPool 管理器和事件通道。四、创建播放器与事件通道实例通道收到create后创建独立播放器和事件通道if(call.methodcreate){constplayerIdcall.argument(playerId)asstring;consteventHandlernewEventHandler(newEventChannel(this.binaryMessenger!,xyz.luan/audioplayers/events/${playerId},),);this.players.set(playerId,newWrappedPlayer(this,eventHandler,this.defaultAudioContext.copy(),this.soundPoolManager!,),);response.success(1);return;}事件通道会发送 prepared、duration、complete、seek complete、current position、log 和 error。位置更新使用定时器只在存在实际播放中的播放器时启动startUpdates():void{this.stopUpdates();this.updateIntervalsetInterval((){this.updateCallback();},200);}stopUpdates():void{if(this.updateInterval!null){clearInterval(this.updateInterval);this.updateIntervalnull;}}没有播放任务后停止定时器可以避免空闲页面持续消耗计时器资源。五、方法映射实例命令按 Dart API 映射到底层播放器switch(call.method){casesetSourceUrl:awaitplayer.setSource(newUrlSource(call.argument(url)asstring,call.argument(isLocal)asboolean,),);break;casesetSourceBytes:player.setSource(newBytesSource(call.argument(bytes)asArrayBuffer),);break;caseresume:awaitthis.startContinuousTask();player.play();break;casepause:player.pause();awaitthis.stopContinuousTask();break;casestop:awaitplayer.stop();break;caseseek:player.seek(call.argument(position)asnumber);break;casesetVolume:player.setVolume(call.argument(volume)asnumber);break;casesetPlaybackRate:player.setRate(call.argument(playbackRate)asnumber);break;casedispose:player.dispose();this.players.remove(playerId);break;}未知或文本 MIME 不能作为音频播放。URL 音源会先按扩展名判断 MIME文本文件会通过错误事件返回而不是让AVPlayer抛出难以理解的底层错误。六、URL 和字节流音源URL 音源区分远程和本地setForMediaPlayer(mediaPlayer:media.AVPlayer):void{if(this.isLocal){constfilefs.openSync(this.url);mediaPlayer.urlfd://${file.fd};}else{mediaPlayer.urlthis.url;}}本地文件通过 fd 加载远程地址交给AVPlayer。字节流音源使用AVDataSrcDescriptor提供读取回调constsource:media.AVDataSrcDescriptor{fileSize:this.bytes.byteLength,callback:(buffer,length,position){if(positionnull||positionsource.fileSize){return-1;}constcopyLengthMath.min(length,this.bytes.byteLength-position,);newUint8Array(buffer).set(newUint8Array(this.bytes.slice(position,positioncopyLength)),);returncopyLength;},};mediaPlayer.dataSrcsource;低延迟 SoundPool 当前不支持任意字节流这种组合会明确抛出不支持错误。七、音频焦点与后台任务播放器通过FocusManager管理音频会话。获得焦点后播放临时失去焦点时暂停并标记恢复状态永久失去焦点时停止等待自动恢复maybeRequestAudioFocus(player:WrappedPlayer):void{conststrategy:audio.AudioSessionStrategy{concurrencyMode:this.getFocusStrategy(),};this.audioSessionManager.activateAudioSession(strategy).then(()player.actuallyPlay()).catch((err:BusinessError){Log.e(TAG,activate failed:${err.code},${err.message});});}后台播放通过 AVSession 和长时任务实现this.sessionawaitAVSessionManager.createAVSession(context,audioplayers,audio,);awaitthis.session.activate();awaitbackgroundTaskManager.startBackgroundRunning(context,backgroundTaskManager.BackgroundMode.AUDIO_PLAYBACK,wantAgentObj,);宿主 HAP 必须配置{ module: { abilities: [ { backgroundModes: [audioPlayback], }, ], requestPermissions: [ { name: ohos.permission.KEEP_BACKGROUND_RUNNING, reason: $string:background_running_reason, usedScene: { abilities: [EntryAbility], when: inuse, }, }, ], }, }同时需要在资源文件中提供权限用途文案。未配置长时任务时切后台后播放可能被系统回收。八、Dart 使用示例多个实例播放finalbackgroundAudioPlayer(playerId:background);finaleffectAudioPlayer(playerId:effect);awaitbackground.setSourceUrl(https://example.com/background.mp3,isLocal:false,);awaitbackground.setReleaseMode(ReleaseMode.loop);awaitbackground.play();awaiteffect.setSourceAsset(sounds/click.wav);awaiteffect.setVolume(0.6);awaiteffect.play();effect.onPlayerComplete.listen((_){effect.dispose();});内存字节流finalplayerAudioPlayer();finalbytesawaitrootBundle.load(assets/audio.wav);awaitplayer.setSourceBytes(bytes.buffer.asUint8List());页面销毁时依次停止并释放播放器awaitplayer.stop();awaitplayer.dispose();九、构建、测试结果验证环境Flutter:3.44.9ohos-0.0.1-canary1OHOS SDK:26DevEco Studio:26.0.0模拟器:emulator 7.0.0.107(SP8DEVC00E999R4P11)验证内容适配包flutter analyze --no-pub通过。主包flutter analyze --no-pub通过。22 个 Dart 测试通过。示例 HAP 构建、安装和启动成功。十、遗留问题setBalance、音效、空间音频和不同音频焦点策略仍需按系统版本验证。HLS、低延迟直播和复杂网络切换需要真机测试。后台播放依赖宿主 HAP 的长时任务和权限配置。audioplayers_android_exo中部分.gitignore是循环符号链接构建工具链扫描全仓库时应排除该目录。示例中的icudtl.dat较大本次远端快照不提交该构建资源。十一、代码提交与协作欢迎加入 CPF-Flutter 鸿蒙社区参与 FlutterOHOS 经验交流。
RELATED

相关推荐

备份只留一份等于没备份?聊聊 NAS 上的 3-2-1 怎么摆

备份只留一份等于没备份?聊聊 NAS 上的 3-2-1 怎么摆

文章目录 📖 介绍 📖 🏡 演示环境 🏡 📒 三份、两种、一份异地:每个数字在家里意味着什么 📒 🧭 先把 3-2-1 拆开 🧱 第一份:本机高频副本,主打「频繁」 🔌 第二份:换一种介质,主打「不同死法」 ☁️ 第三份:真异地,主打「场所不在了」 🧪 两个「看…

📅 2026/10/22 17:54:11
企业 AI 交付的五个协作接口:字段级清单与验收硬线

企业 AI 交付的五个协作接口:字段级清单与验收硬线

企业 AI 交付的五个协作接口:字段级清单与验收硬线 企业 AI 项目最常见的失败形态不是跑不起来,是跑起来了没人用。系统在线,接口正常,监控没报警,业务侧的实际操作仍然停在旧流程上。这种状态在合同里不算失败&#x…

📅 2026/10/22 17:54:11
远程升级zynq/zu47的qspiflash裸机

远程升级zynq/zu47的qspiflash裸机

1)上电完成读取qspi flash的型号 根据地址0x9F,调用qspi flash底层函数 xqspips_polledtransfer,实现读取4字节,1、2、3字节有效,0字节可舍去,读到的数据如0x21,0xBA,0x20。 2&#…

📅 2026/10/22 17:49:09
MORE NEWS

更多资讯

📰

Java+Spring Boot实现老年人健康管理应用:从数据模型到预警推送

简介:面向老年健康管理场景的Java应用设计源码,回应老龄化背景下慢性病与日常健康监护需求,适合Java Web开发者学习或快速搭建同类健康管理原型,也可作为课程设计或毕业设计的参考。资源包共36个文件,压缩后仅120KB&am…

📰

SSM架构的老年人健康管理Java项目源码拆解:分层设计与核心模块解析

简介:在人口老龄化背景下,老年健康管理应用需求持续增长。基于Java平台的老年人健康管理应用设计源码,是一份面向健康管理场景的完整Java项目,适合Java初学者、课程设计与毕业设计参考。源码包共36个文件、120KB,以30个…

📰

免费用户即可体验:GPT-6让对话直接生成可交互界面

很多人可能今天一打开对话框就发现:界面好像哪里不一样了。不是多了个按钮,也不是换了个皮肤,而是你问完一个问题之后,回答区域不光有文字,还直接“长出”了一个可以交互的界面——一个能计算、能勾选、能填写的组件&a…

📰

基于YOLOv12的安检X光图像危险物检测系统实战

安检X光图像里的危险物检测,一直是计算机视觉里比较特殊的一个方向。常规目标检测要考虑的是“这个东西是什么”,而安检场景还要叠加一层“这个东西在层层叠叠的行李里面,到底藏了什么”。最近我把整套流程用YOLOv12从前到后跑了一遍&#xf…

📰

AI周报实战:信息降噪与趋势拆解方法论

1. 为什么我要做一份“AI 周报”这种反人性的事先坦白讲,做周报这件事本身就挺反人性的。我在一线做技术方案和产品落地十来年,最烦的就是每周五下午被各种周报模板折磨。但有意思的是,从去年开始,我自己主动开始写一份“AI 周报”…

📰

Java文档处理工具链实战:Word/PDF生成、转换与图片渲染全解析

1. 文档处理工具链的整体设计思路 1.1 为什么选择 Java 作为文档处理的主力语言 在服务端做文档生成和格式转换,Java 生态的成熟度是其他语言很难比的。我做过好几个类似的项目,从最简单的导出 Word 报表,到复杂的合同批量生成、发票 PDF 渲…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬