CHANGELOG.md
2.85 KB
更新日志(CHANGELOG)
本文件记录每次功能迭代内容。
2026-11-05 音频播放稳定性修复(app-feature-2610-ios)
本次聚焦 lib/services/player_service.dart(H5 音频播放服务)的异常自愈重写,
解决线上 iOS 报 WAVEAudioFile::OpenFromDataSource Failed 后播放器永久卡死、
无法播放新音频的问题。对外方法签名、H5 消息结构(audioProgress/audioEnd)、
异常契约均保持不变。
问题根因(已核实 flutter_sound 9.30.0 源码)
- 插件 iOS 远程播放分支:native 异步下载后立即返回成功,下载回调忽略 NSError,
失败分支从不通知 Dart →
await startPlayer()永久悬挂且无任何异常; - 悬挂持有插件内部锁,导致实例所有方法(stop/pause/resume/seek/close)全部死锁;
- 服务端音频格式标注混乱:URL/Content-Type 标 mp3,实际内容为 WAV、 MP3-in-WAV(wFormatTag=0x55)或 WAV 头长度字段损坏,均会导致 AVAudioPlayer 拒绝播放。
修复内容
-
播放器异常自愈:
startPlayer失败(抛异常/超时)→ 销毁重建播放器 → 用新实例重试一次 → 仍失败则复位为未初始化态并抛原始异常, 保证"底层报错后不影响下一次新播放"; -
远程音频自主下载:http(s) 音频先用
dart:io HttpClient下载到本地临时文件再播放, 绕开插件远程分支缺陷(含幽灵播放隐患);下载带浏览器 UA、 Content-Type 校验(拦截防盗链/鉴权错误页)、空文件校验、半成品清理; - 全链路超时兜底:下载/建连 10s、startPlayer/openPlayer 10s、 常规操作(暂停/恢复/进度/倍速/停止/关闭)3s,任何悬挂都能在有限时间内 放弃旧实例走重建,不再永久死锁;超时后旧实例接受泄漏;
- 音频格式自动识别:按文件头魔数(mp3/wav/ogg/flac/caf/m4a/aac) 修正临时文件扩展名,避免错误扩展名误导 AVAudioPlayer 选错解析器;
- WAV 头修复:RIFF/data 长度字段与实际字节不符(流式占位 0xFFFFFFFF、 奇数未对齐等)时按实际字节重写规范头,正常文件不做修改;
- MP3-in-WAV 剥离:识别 wFormatTag=0x55(MP3 数据套 WAV 容器, AVAudioPlayer WAVE 解析器不支持)时剥离容器、另存为纯 MP3 播放;
- 其他加固:playId + 播放代次双重快照防陈旧 whenFinished 回调误杀新播放; playAudio/stopAudio 串行锁防并发重建;临时文件生命周期管理 (换曲成功后删上一首、清理/复位时删当前);关键路径诊断日志 (下载状态/格式识别/WAV 头详情/失败文件头 16 字节)。
影响范围
- 仅修改
lib/services/player_service.dart,无新增依赖; - Android/iOS 通用:远程音频统一走本地文件播放路径。