onEnded不触发主因是平台对音频生命周期处理差异,如切后台、页面销毁致音频被强制暂停;应主动控制播放状态并兜底,而非依赖回调。

uni.createInnerAudioContext().onEnded 不触发的常见原因
这不是 uni-app 的 bug,而是各平台对音频生命周期的处理差异导致的。最典型的情况是:音频还没真正“播完”,就被系统强制暂停(比如切后台、页面销毁、src 被重设),onEnded 就永远不会触发。
微信小程序里,uni.createInnerAudioContext() 在页面 onHide 或切后台时会被静默终止;支付宝/字节等平台更激进,只要页面不可见,音频上下文就直接失效,连 onError 都可能不抛出。
- 不要依赖
onEnded做资源清理或状态同步——它只在自然播完时可靠 - 页面跳转前务必手动调用
audio.pause()或audio.stop(),再执行清理逻辑 - 监听
onStop和onError作为补充,但注意支付宝平台这两个事件也常失灵 - iOS 真机上若音频被系统中断(如来电、闹钟),
onStop可能延迟几百毫秒才触发,不能当作即时响应依据
如何确保音频停止后必有回调
根本解法是放弃等待系统回调,改为主动控制 + 状态兜底。关键点在于:把“停止”这个动作变成可预测、可追踪的明确操作。
- 所有播放入口统一走一个封装函数,例如
playAudio(src),内部记录当前正在播放的src和实例引用 - 每次新播放前,先调用
prevAudio?.pause(),再prevAudio?.destroy(),避免残留 - 在
onHide、onUnload、onBackPress等生命周期钩子中主动触发停止逻辑,并更新全局播放状态 - 加一个定时轮询兜底(仅限 H5/APP):
setInterval(() => { if (audio.playing && !audio.paused) checkPlaybackProgress(); }, 500),用于发现异常卡顿或假播放
微信小程序后台音频必须用 BackgroundAudioManager
如果你的目标是“用户切后台后音频还能继续播”,那 uni.createInnerAudioContext() 从根子上就不适用——它压根没设计支持后台场景。
只有微信小程序提供 uni.getBackgroundAudioManager(),且必须满足三个硬性条件才会真正在后台持续运行:
-
manager.src必须赋值后再调用manager.play(),只设 src 不 play 是无效的 -
manager.title、manager.singer、manager.epname至少填一项,否则 iOS 锁屏界面不显示控件 - 不能混用
uni.createInnerAudioContext()和uni.getBackgroundAudioManager()—— 同一页面内二者互斥,后者会抢占音频焦点 - 其他平台(支付宝、字节、快应用)目前无等效接口,切后台必停,无法绕过
APP 端音频中断无回调的特殊处理
Android/iOS 打包成 App 后,音频可能被系统策略中断(比如来电、低电量模式、省电策略),此时 onStop 或 onError 往往静默失败。
实操上只能靠组合判断:
- 监听
plus.runtime.getProperty('backgroundMode'),检测是否进入后台 - 在
plus.audio.getPlayer()(原生音频)或uni.getBackgroundAudioManager()(仅微信)中注册onStateChange回调(App 端可用) - 对关键音效(如扫码提示音),播放后立即启动一个 3 秒倒计时,超时未触发
onPlay就认为失败,重试或降级提示 - 避免在
onPause中做耗时操作——App 挂起时 JS 线程可能被冻结,回调永远不执行
音频停止不回调的本质,是平台把“播放权”收走了,而不是你的代码漏写了监听。重点不是补监听,而是提前接管生命周期,别等系统通知你才行动。


















