uni-app锁屏后定时器失效是因系统节流或挂起js线程,ios冻结、安卓精度差;应通过onhide/onshow记录时间戳与剩余时间,用settimeout续计时,禁用setinterval,并优先采用本地通知等系统级方案。

uni-app锁屏后定时器失效,不是系统设置问题
uni-app里出现“锁屏时间显示和实际不符”,大概率不是手机系统时间不准或电源设置不一致,而是setTimeout和setInterval在App后台/锁屏状态下被系统节流甚至挂起。iOS会直接暂停JS线程,Android各厂商策略不同(华为、小米常大幅降低定时器精度),导致倒计时跳变、延迟、卡死甚至完全停止。
onHide/onShow里存取时间差才是正解
不能依赖定时器持续运行,得靠生命周期+时间戳比对来“续命”。核心逻辑是:锁屏时记下剩余毫秒数,唤醒时重新计算并启动新定时器。
-
onHide中保存当前时间戳和剩余倒计时值(比如localStorage.setItem('countdownLeft', leftMs)) -
onShow中读取上次保存的leftMs,再用Date.now() - lastHideTime算出后台经过时长 - 用
leftMs - passedMs得到真实剩余时间,大于0就用setTimeout继续(别用setInterval) - 务必用
setTimeout而非setInterval——后者在后台恢复后可能批量触发,造成时间“加速”
安卓/iOS行为差异必须区分处理
iOS后台JS几乎完全冻结,onHide到onShow之间的时间差就是真实挂起时长;安卓部分机型(如OPPO、vivo)可能仍允许低频JS执行,但精度极差。所以统一按“完全暂停”逻辑处理最稳妥。
- iOS:
onHide后可立即清空所有定时器ID,避免残留 - 安卓:即使
onHide没触发(某些定制ROM),也要在onShow里做兜底校验,防止leftMs为负 - 不要依赖
plus.navigator.setScreenLock这类原生API控制锁屏——它只影响屏幕开关,不影响JS执行环境
本地通知替代纯JS倒计时
如果需求是“X分钟后提醒用户”,纯前端倒计时不可靠。优先走系统级方案:
- App端用
uni.showLocalNotification(需配置permission和后台权限) - 鸿蒙/Android 12+需声明
POST_NOTIFICATIONS权限,iOS需在Info.plist加UIBackgroundModes - 服务端推送+本地缓存兜底:倒计时到0时,若App未激活则发离线通知;若已激活,则
uni.showToast提示
真正难的不是写倒计时代码,而是接受“JS在后台不可信”这个事实——所有依赖精确后台计时的逻辑,都得重构为事件驱动或系统能力调用。











