Flutter 鸿蒙使用实战:用 audioplayers 三方库给应用加上音频播放与进度控制

Flutter 社区地址: https://atomgit.com/CPF-Flutter/flutter_flutter
github三方库地址:https://github.com/bluefireteam/audioplayers
pub地址:https://pub.dev/packages/audioplayers
鸿蒙适配版:https://atomgit.com/CPF-Flutter/flutter_audioplayers
示例工程地址:https://atomgit.com/weixin_52908342/audio_demo

库版本:audioplayers 6.5.1(CPF-Flutter 鸿蒙适配版,commit b853cda)|验证环境:Flutter 鸿蒙 SDK 3.44.9(oh-3.44.9-dev)|DevEco Studio 26.0.0.821 | 设备:DevEco 模拟器 Pura X View | HarmonyOS 7.0.0.106(API 26)

应用里的提示音、语音播报、按键音效、短音频动效几乎离不开音频播放。audioplayers 是 Flutter 生态里月下载 70 万级的主流音频库,CPF-Flutter 社区已在 flutter_audioplayers monorepo 里完成鸿蒙适配(audioplayers_ohos 平台包)。本文介绍它在 OpenHarmony 上的引入方式、播放控制与事件流监听的全接口调用,以及在 DevEco 模拟器上播放资产音频的真实运行效果。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

一、环境搭建

本章不重复展开,直接引用官方文档:Flutter OH 开发环境搭建指导

完成后用 flutter doctor -v 验证,FlutterHarmonyOS toolchain 两项均为 [√] 即可。本文实际使用版本:Flutter OH oh-3.44.9-dev(commit 77e0c8d13b)、DevEco Studio 26.0.0.821、HarmonyOS SDK API 26。
在这里插入图片描述

二、应用背景

在这里插入图片描述

2.1 当前的应用场景与痛点

  • 语音提示类:扫码成功音、消息提示音、导航播报
  • 媒体类:播放本地/网络音频、逐句跟读、有声书
  • 游戏/互动类:按键音效、动效反馈音
  • 儿童教育类:字母卡片发音、跟读评分

痛点:Flutter 官方 audioplayers 只覆盖 Android/iOS/Web/macOS/Linux/Windows 六端,鸿蒙侧此前需自己写 ArkTS 播放器——现在 CPF-Flutter 已提供 audioplayers_ohos 平台包,开箱即用。

2.2 为什么需要这个库

自己写鸿蒙播放器要处理 AVPlayer 状态机、prepare/start/stop 生命周期、seek 精度、事件回调桥接;audioplayers 的鸿蒙适配版由社区维护,API 与其他平台完全一致,业务代码零改动迁移。

2.3 解决什么问题

一句话总结:让 Flutter 应用在鸿蒙上以与 Android/iOS 完全相同的 API 播放、控制、监听音频。具体提供:

  1. 播放控制:play / pause / resume / stop / seek
  2. 音量调节:setVolume
  3. 五个事件流:状态 / 时长 / 进度 / 播放完成 / seek 完成
  4. 多来源:AssetSource(资产)/ UrlSource(网络)/ DeviceFileSource(本地文件)

三、功能介绍

功能API说明适用场景
播放资产play(AssetSource('audio/x.m4a'))播放打包进应用的音频提示音、内置音效
播放网络play(UrlSource('https://...'))流式播放在线音频在线音乐、播客
暂停/继续/停止pause() / resume() / stop()播放控制三件套播放器 UI
进度跳转seek(Duration)跳到指定位置,onSeekComplete 回调进度条拖动
音量setVolume(0.0~1.0)0-1 浮点音量滑条
状态流onPlayerStateChangedplaying/paused/stopped/completedUI 状态联动
时长/进度流onDurationChanged / onPositionChanged毫秒级 Duration进度条实时刷新
完成事件onPlayerComplete单曲播完触发自动连播/循环

四、使用方法

4.1 在应用中引入三方库(AtomGit 链接方式)

dependencies:
  audioplayers:
    git:
      url: https://atomgit.com/CPF-Flutter/flutter_audioplayers.git
      ref: b853cdafdef1549be31b478a954f6d8b36d314e6
      path: packages/audioplayers

dependency_overrides:   # 关键!锁 ohos 实现包与接口包到同一 commit
  audioplayers_ohos:
    git:
      url: https://atomgit.com/CPF-Flutter/flutter_audioplayers.git
      ref: b853cdafdef1549be31b478a954f6d8b36d314e6
      path: packages/audioplayers_ohos
  audioplayers_platform_interface:
    git:
      url: https://atomgit.com/CPF-Flutter/flutter_audioplayers.git
      ref: b853cdafdef1549be31b478a954f6d8b36d314e6
      path: packages/audioplayers_platform_interface

执行 flutter pub getimport 'package:audioplayers/audioplayers.dart';

三个注意点:

  1. 必须用 dependency_overrides:audioplayers 是 federated 插件(主包 + 各平台实现包 + 接口包)。若不锁 audioplayers_ohos 到同 commit,pub 可能解析到无鸿蒙实现的旧版本,运行时报 MissingPluginException
  2. path 必须写子包路径packages/audioplayerspackages/audioplayers_ohos),不能只写到仓库根
  3. ref 写 commit hash(本文 b853cda),tag/分支名可能随上游推进漂移

4.2 调用接口实现功能

4.2.1 AudioPlayer 实例与事件订阅
final player = AudioPlayer();

player.onPlayerStateChanged.listen((s) { /* PlayerState.playing 等 */ });
player.onDurationChanged.listen((d) { /* 总时长 */ });
player.onPositionChanged.listen((p) { /* 当前进度 */ });
player.onPlayerComplete.listen((_) { /* 单曲播完 */ });
player.onSeekComplete.listen((_) { /* seek 完成 */ });

运行效果

初始停止状态
demo 首屏(a1):蓝色 AppBar + 灰色停止图标 + 大字"已停止" + PlayerState.stopped + 时间 0:00 / 0:00。下方 seek 进度条、四个控制按钮(播放/暂停/继续/停止)、音量滑条、暗色事件流卡(等待事件)

4.2.2 play / pause / resume / stop:播放控制

功能说明play(Source) 加载并播放;pause() 暂停;resume() 从暂停处继续;stop() 停止并复位。

// 播放资产音频(pubspec 的 flutter.assets 已声明 assets/audio/)
await player.play(AssetSource('audio/demo.m4a'));

await player.pause();    // 暂停
await player.resume();   // 继续
await player.stop();     // 停止

运行效果

播放中状态
点击"播放"后(a2):蓝色播放图标 + 大字"播放中" + PlayerState.playing + 时间 0:03 / 0:03(onPositionChanged 每秒刷新)。事件流日志三连:onPlayerStateChanged → playingplay(AssetSource demo.m4a)onDurationChanged → 3529ms(音频总长 3.5 秒)——三个流全部真实触发

4.2.3 seek + setVolume:进度与音量

功能说明seek(Duration) 跳转播放位置(触发 onSeekComplete);setVolume(0.0~1.0) 调节音量。

// 进度条拖动到 40% 处
await player.seek(Duration(milliseconds: (0.4 * durationMs).round()));

// 音量调到 60%
await player.setVolume(0.6);

demo 中进度条 Slider.onChanged 直接调 seek,音量滑条实时调 setVolume,两者动作均写入事件流日志。

4.2.4 onPlayerComplete:播放完成

功能说明:音频自然播完时触发(区别于手动 stop())。

player.onPlayerComplete.listen((_) {
  print('本条音频播放完成');
  // 自动播下一条 / 循环 / 解锁 UI
});

运行效果

播放完成状态
3.5 秒音频自然播完后(a3):绿色勾图标 + 大字"播放完成" + PlayerState.completed + 时间回到 0:00 / 0:03。事件流日志新增 onPlayerComplete(播放完成)onSeekComplete(demo 的 stop 复位触发)——完成事件真实回调到 Dart 层

4.3 完整示例代码

完整工程(含资产音频 assets/audio/demo.m4a)已开源:https://atomgit.com/weixin_52908342/audio_demo,clone 后 flutter pub get && flutter build hap --debug 即可在模拟器复现本文全部效果。

核心状态管理(可复制骨架):

class _AudioPageState extends State<AudioPage> {
  late final AudioPlayer _player;
  PlayerState _state = PlayerState.stopped;
  Duration _pos = Duration.zero, _dur = Duration.zero;
  double _volume = 1.0;
  final List<StreamSubscription> _subs = [];

  
  void initState() {
    super.initState();
    _player = AudioPlayer();
    _subs.addAll([
      _player.onPlayerStateChanged.listen((s) => setState(() => _state = s)),
      _player.onDurationChanged.listen((d) => setState(() => _dur = d)),
      _player.onPositionChanged.listen((p) => setState(() => _pos = p)),
      _player.onPlayerComplete.listen((_) => log('播完')),
      _player.onSeekComplete.listen((_) => log('seek 完成')),
    ]);
  }

  
  void dispose() {
    for (final s in _subs) { s.cancel(); }
    _player.dispose();
    super.dispose();
  }

  Future<void> _play() =>
      _player.play(AssetSource('audio/demo.m4a'));
}

签名与构建(活动硬性要求 signingConfig: "default"):

flutter create --platforms ohos .
# ohos/build-profile.json5 的 app.signingConfigs 填入 DevEco 自动签名材料
flutter build hap --debug
hdc install build/ohos/hap/entry-default-signed.hap
hdc shell aa start -b com.example.audio_demo -a EntryAbility

五、FAQ:使用问题

Q1:运行时报 MissingPluginException: No implementation found for method ...

dependency_overrides 没锁 audioplayers_ohos,或锁的 commit 不含 ohos 平台。确认三包(主包 / audioplayers_ohos / audioplayers_platform_interface)都在 overrides 里且 ref 一致(本文 b853cda),然后 flutter clean && flutter pub get 重新构建。

Q2:播放资产音频报 Unable to load asset

pubspec.yamlflutter.assets 段没声明资产目录,或路径大小写不对:

flutter:
  assets:
    - assets/audio/    # 目录尾斜杠 = 整目录打包

Q3:模拟器上听不到声音

DevEco 模拟器音频输出依赖宿主机——确认 Mac 本身没静音。demo 的 UI 状态与事件流不依赖扬声器(进度/状态照常刷新),本文三张截图即模拟器真实运行效果。

Q4:onDurationChanged 只触发一次,进度不动

  • onDurationChanged 本来就只在加载/时长变化时触发(一次正常)
  • 进度要看 onPositionChanged(播放中持续推送)
  • onPositionChanged 不动:确认 play() 成功(状态流先到 playing)、没误调 stop()

Q5:连续快速 play 同一资产有杂音/重叠

audioplayers 6.x 单实例复用需先 stop();或使用 AudioPool(低延迟音效场景,提示音/按键音推荐):

final pool = await AudioPool.create(source: AssetSource('audio/click.mp3'));
pool.start();

Q6:鸿蒙端与 Android 端行为差异

  • 鸿蒙侧由 audioplayers_ohos 基于 @ohos.multimedia.media.AVPlayer 实现,release() 行为与 Android 一致
  • 网络播放(UrlSource)需在 module.json5 声明 ohos.permission.INTERNET(demo 已含)
  • setPlaybackRate / setReleaseMode(循环)在鸿蒙侧的支持进度以 flutter_audioplayers 仓库 的 CHANGELOG.OpenHarmony.md 为准

Q7:发现库的问题怎么反馈?

  • 提 Issue:到 CPF-Flutter/flutter_audioplayers → Issues → 新建,正文四要素:复现步骤 / 期望 / 实际 / flutter --version + 设备系统版本 + hilog 关键日志
  • 提 PR:Fork → 建分支 → 修复提交 → push → 在 AtomGit 发 PR,描述附鸿蒙设备验证截图

六、其他内容

audioplayers 6.5.1 鸿蒙适配版开箱即用:federated 三包锁同一 commit 后,播放控制、seek、音量、五个事件流全部与 Android/iOS 行为一致。Demo 在 DevEco 模拟器(HarmonyOS 7.0.0.106 / API 26)上真实验证了播放→完成全流程,事件流逐条实时回调。对比自研 ArkTS 播放器(AVPlayer 状态机 + 通道桥接),一行 git 依赖就获得跨端一致体验,是鸿蒙 Flutter 应用音频需求的默认选择。

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐