开发手记

都2026年了,让助眠应用整夜播放竟然还是这么难

我只是想让手机发出风扇声,一直响到天亮。到了2026年,这应该算是解决了的问题吧。结果,它占用了我作为开发者意想不到的时间。

我用了很多年White Noise Lite。有广告,界面在我看来也很老,但大多时候能用,这才重要。后来它开始频繁停下来。我把这些情况当作崩溃,但没有日志,无法知道真正原因。我也想要现代一点的界面,以及在设备上生成而非播放录音的声音,还能细致调节。于是我做了Veil,也真正体会到可靠性问题有多难。

iOS的后台播放相对直接,以我自己的经验,Veil从一开始就很稳定。Android则成了长期工程:硬件五花八门,有内存少的老手机,有厂商各自的电池管理,还有播放途中安装的更新。我自己的代码也有不少问题。对凌晨三点醒来的人来说,这些区别并不重要。

我从崩溃报告入手,很快发现需要更多上下文。被终止的进程可能来不及报告异常,活着的进程也可能只有无声的音频流。即便有前台服务和播放通知,也不能证明扬声器真的在响。我添加了原生播放日志、进程退出信息、内存测量、服务状态、音频流事件,以及明确的主动停止记录。相关证据会在进程结束后保留下来,等下次启动时收集。

目标是尽量还原一晚的经过,区分可能的原因。当时是否仍然应该播放?计时器是否结束?内存是否增长?手机是否充电?Android是否替换了应用包?更多信号有帮助,但前提是知道每种信号到底能说明什么。

最早需要修复的,其实是测量本身。从最近任务里划掉Veil,可能停止了声音,却没正确关闭记录中的会话。几小时后Android回收缓存进程,我的报告就把它算成播放故障。早晨主动停止,变成了“夜间被杀”。而真正打断播放的更新,反而被当作正常系统退出排除了。

修正这些定义后,还没继续修音频代码,故障图景就变了。此后我一直区分播放改善和测量改善。我定期按版本、设备系列、会话时长和退出原因分析,排除测试设备并去重。延迟上报也很重要:新版跑过几段短会话,并不能说明它能撑过一晚。

这些模式指导真机测试。我在实体手机上做长时间和整夜测试,也使用Samsung远程实验室,持续采集logcat、内存和内存压力,并在故障时保存音频与服务状态。这样不用我亲眼撞见故障,也能拿到证据。

测试环境本身也会影响结果。USB会供电,所以连着USB并不是拔掉电源后的电池测试。反复运行dumpsys meminfo甚至可能引起声音异常。一晚正常,只能说明在那些条件下没复现故障,不代表所有设备和系统状态都没问题。

一个意外发现是Android Auto Backup。在我的Pixel上,系统日志记录了播放期间BackupManager因备份终止Veil进程。回看整体安装数据,2026年8月14日至9月11日期间,93个安装中出现了190次受保护进程的SIGKILL,重复间隔集中在三天左右。这支持备份这一解释,但不能证明每次退出都由它造成。

我关闭了Auto Backup,接受了云端恢复方面的取舍。Android文档说明备份会关闭应用,同时通常排除前台应用。正是设备上的实际记录,让这个具体案例有了可执行的解决方向。Android备份文档

另一些问题在我自己的代码里。旧音频上下文尚未关闭时,恢复逻辑就开始创建新上下文,在应用已经出问题时又叠加了资源。现在会在有限时间内等待清理完成,并将恢复与播放操作串行处理。恢复也必须尊重更新的用户意图:修复排队时用户按了停止,就不能修完又把声音打开。

一次修复还引入了新问题。我加了150毫秒的探测,检查音频上下文的时钟是否前进,以识别那些自称运行中却卡住的上下文。但它等待的是JavaScript计时器。在后台,这个等待可能一直卡到应用回到前台。现在探测只在前台运行。这也是恢复路径必须在熄屏状态测试的原因。

一些最有效的改动其实是产品决定。真机测量显示,广告WebView进程关联着约90 MB额外常驻内存。更早的调查也发现过严重的SDK相关内存故障。我先试着控制成本,后来干脆移除了广告和SDK。对需要整夜运行的应用,可靠性更重要。

遥测仍缺少一个关键信息:用户是否预期声音会停。发生相关中断后,Veil可以显示带时间的小卡片,问“这次停止在你的预期之内吗?”这个措辞是有意的。“是你停止的吗?”会漏掉伴侣停止播放,或本人没操作但预料到中断的情况。

如果是预期内的停止,就不把用户带去排查电池。如果不是,应用会承认中断,并根据现有证据提供帮助。回答直接反映体验,但不假装能确定技术原因。也无需让每位新Android用户一上来就面对吓人的权限提示和电池设置寻宝。

这些设置对双方都麻烦。我可以打开设置,或在适当时请求豁免,但决定权在用户手里。Android的豁免流程也不能控制所有厂商的清理行为。出问题后给一个具体步骤,比第一次播放前就让人翻陌生设置更有用。Android电源管理指南

更新尤其令人无奈。我可以指引用户找到Play里单个应用的自动更新设置,但Veil不能控制它。手动更新增加了负担,Google也为关键安全更新保留例外。一次为了改善夜间稳定性的更新,本身就可能打断那一晚。Google Play更新设置

更新后的自动恢复还没做完。不只是重建音频图,计时器状态和用户意图也必须正确保留。某些厂商特有的模式还需要更好的复现,才能有把握地解释。我希望应用从故障中恢复,而不是跟主动停止它的人较劲。

最大的进展来自定期分析、长时间真机测试、针对性修复和直接反馈的结合。每一种都能发现其他方法遗漏的东西。我越来越不在意应用是否声称正在播放,而更在意有什么证据。睡前按下播放的人应该能放心相信它,尽管做到这一点比我想的费力得多。

想找适合你手机的具体操作?请看配套指南:解决Android音频中断。