文章

微信小程序开发踩坑(二)

AI 摘要

在我之前的文章 《微信小程序原生开发的音频痛点》 中,我曾提到过微信小程序开发白噪音、冥想类应用时面临的“死局”:

“想要混音+连贯播放,最好的选择是 InnerAudioContext,但一旦退出或锁屏就会停止;而选择系统层的 BackgroundAudioManager,虽然允许后台播放,但不能混音,且每次循环都会有明显的加载停顿。”

为了实现产品最核心的“锁屏播放”功能,我们往往不得不向 BackgroundAudioManager 妥协。那么今天这篇,我们就来深究一下这个让人抓狂的技术细节:为什么它连最基本的“无缝循环播放”都做不到?

很多开发者以为是自己的代码没写好,但实际上,这种卡顿是由小程序的底层架构和 API 设计共同造成的“物理级”硬伤,主要有以下三大元凶:

1. API 的缺失

在普通的音频开发中,实现无缝循环只需要一个简单的 loop = true 属性,但操蛋的是,微信根本没有给 BackgroundAudioManager 提供 loop 参数。这就导致开发者只能被迫走一条弯路:监听音频的 onEnded(自然播放结束)事件,然后在回调函数里,手动给 src 重新赋值来触发下一次播放。正是这条弯路,引爆了后面的灾难。

2. JSBridge 跨进程通信延迟

微信小程序采用的是逻辑层(JS)和渲染层/原生层(Native)分离的双线程架构。

当你被迫用 onEnded 手动循环时,指令的流转是这样的:

  1. 手机底层播放完毕,发信号给微信客户端。
  2. 微信通过底层 JSBridge 跨进程通知你的小程序 JS 触发 onEnded。
  3. 你在 JS 里执行 audio.src = 'xxx' 。
  4. 指令再次跨进程发回给微信客户端,最终调用系统 API 重播。

在单线程环境只需几毫秒的操作,在小程序的跨进程通信中,一来一回通常会消耗 100~500毫秒。在这段通信时间里,扬声器就是一片死寂。

3. 系统级媒体中心的销毁与重建

BackgroundAudioManager 之所以能后台播放,是因为它直接接管了手机操作系统(iOS/Android)的锁屏媒体控制中心

当一首歌彻底结束(触发 onEnded),系统会认为当前的音频任务已经终结。当你在零点几秒后再次给 src 赋值时,底层并不只是简单地“重新播放声音”,而是经历了一次重建:

  • 销毁旧的音频会话(Audio Session)。
  • 重新读取音频资源、title、封面图等元数据。
  • 在系统层级构建一个新的播放任务,并刷新锁屏UI。

这种系统级资源的“销毁再重建”非常缓慢,将原本跨进程通信带来的停顿感又放大了数倍。

总结

BackgroundAudioManager 的循环卡顿,是 API 缺失 + 跨进程通信延迟 + 操作系统级媒体重置 共同压迫的结果。这不是靠前端代码的奇技淫巧就能抹平的逻辑问题,在官方开放更底层的 API 之前,这依然是微信小程序生态里一个无解的痛。