openGym训练时屏幕常亮原理Wakelock锁屏机制完整解析【免费下载链接】openGymSelf-hosted gym body-weight tracker — plan routines, log workouts (supersets, warm-ups, cardio), see which muscles are trained, fatigued or detrained, import from FitNotes/Strong/Hevy, passkey login. Your data, your server.项目地址: https://gitcode.com/GitHub_Trending/op/openGymopenGym 是一款自托管self-hosted的健身训练记录应用其中的Wakelock 锁屏机制能在训练全程让手机屏幕常亮——组间休息、翻动作库、看统计都无需反复解锁。本文完整解析它是如何基于浏览器 Screen Wake Lock API 实现的为什么“一次性请求”会悄悄失效、openGym 如何自动重新上锁、以及在哪些环境下该功能会不可用。一、为什么训练时屏幕常亮很重要想象一下两组卧推之间你低头看手机确认下一组的重量屏幕却因为锁屏超时熄灭了——解锁、点回来、再找位置打断的正是训练的连贯节奏。openGym 的引导式训练界面Guided Workout会自动开始当日训练、预填上次重量、组间运行休息计时器。如果此时屏幕黑了整套体验都会被打断。因此 openGym 内置了“Keep screen awake保持屏幕常亮”开关在训练会话期间通过 Wake Lock 锁屏机制阻止屏幕自动熄灭。二、功能入口在哪里打开屏幕常亮开启路径很简单设置 → 训练中During a workout→ Keep screen awake对应的界面实现位于 Settings.jsx开关状态保存在应用设置项keepAwake中默认为开启见 useStore.js。有两点值得注意浏览器不支持时开关会禁用界面通过wakeLockSupported()检测浏览器是否提供 Wake Lock API不支持时显示 “Not supported in this browser.”锁定与“训练会话”绑定而不是与“训练页面”绑定App.jsx 中的注释写得很清楚——训练中切到 Stats 页面看一眼数据屏幕依然保持常亮直到训练真正结束。三、核心机制57 行代码搞定“永不黑屏”整个 Wakelock 锁屏机制的核心实现集中在一个不到 60 行的模块wakelock.js。它依赖的是 Web 标准的Screen Wake Lock APInavigator.wakeLock.request(screen)。3.1 陷阱一次性请求为什么“悄悄失效”文件开头的注释点出了关键问题浏览器会在文档不可见时切换标签页、应用退到后台、手动锁屏主动丢弃锁。一次性请求只生效一次然后就悄无声息地失效了。也就是说如果代码只是简单地request()一次用户切个 Tab 再回来锁就已经没了——而且不会有任何报错提示。3.2 openGym 的解法状态 监听 自动重连模块用三个模块级变量维护“上锁意图”变量含义wanted我们当前是否想要屏幕常亮自己的意图标志sentinel当前持有的WakeLockSentinel没持有锁时为nullpending是否有一个request()正在飞行中防止重复叠加请求配合 acquire() 函数 的防御逻辑形成完整的锁屏机制前置检查不想要锁、已持有锁、已有请求在飞行中、浏览器不支持、文档不可见——任一条件成立直接返回文档不可见时request()会直接被浏览器拒绝。请求落地的竞态处理await期间如果用户已经调用了releaseWakeLock()返回的锁会被立即释放绝不泄漏。静默容错catch分支里注释写道——“iOS 在低电量模式下会拒绝一些浏览器在低电量时也会拒绝。没什么可做的安静失败等文档下次变为可见时再试。”自动重连注册visibilitychange监听器onVisible只要文档重新变为可见且仍处于训练会话中就重新acquire()。3.3 React Hook训练开始上锁结束放锁模块最后导出一个 useWakeLock(enabled) Hookenabled为真时请求锁组件卸载或条件变假时释放。在 App.jsx 中的接线方式是useWakeLock(!!S.active !S.active.editingWorkoutId S.keepAwake ! false)翻译成人话有进行中的训练 不在编辑界面 用户没有手动关闭开关三者同时满足就保持锁屏常亮。四、测试如何保证“切个Tab锁就丢”的坑被填上配套的测试文件 wakelock.test.js 的思路很值得学习既然整个模块的意义就是“扛住浏览器的自动丢锁行为”那么假浏览器也必须真的会丢锁——否则测试会放过一个“切一次标签页就死掉”的一次性实现。测试覆盖了几个关键场景✅ 训练开始能拿到锁且不会叠加第二把锁✅ 文档不可见时不会发起请求✅ 退到后台被浏览器丢锁后回前台自动重新获取requests从 1 变成 2✅ 被系统拒绝模拟 iOS 低电量模式后保持静默回前台自动重试✅ 请求“飞行中”时释放锁不会泄漏一把没人持有的锁✅releaseWakeLock()之后停止自动重连五、环境限制哪些情况下开关会“置灰”官方文档对这两个坑有明确说明部署时建议提前了解5.1 传输协议要求HTTPS 或 localhostdocs/SELF_HOSTING.md 指出Wake Lock API 只在HTTPS 或http://localhost下可用。如果你的自建实例通过纯局域网 IP如http://192.168.x.x访问开关会显示为不受支持。服务端无需任何额外配置。 这正是文章配图里架构层强调端到端 TLS 的原因之一——对普通用户而言配好 HTTPS 是解锁该功能的正确姿势。5.2 移动端的前台服务兜底在原生壳Capacitor 打包的 Android/iOS 应用里Android 侧另有兜底前台服务会在休息倒计时期间持有系统 wake lock保证屏幕锁定的情况下休息结束的铃声也能准时响起详见 docs/MOBILE.md。而 iOS 在低电量模式下会拒绝屏幕锁请求属于系统行为openGym 会静默降级。六、总结openGym 的屏幕常亮功能麻雀虽小五脏俱全一个意图标志wanted把“用户想不想常亮”和“锁还在不在”彻底解耦visibilitychange 自动重连专治浏览器“悄悄丢锁”️pending/sentinel 竞态防护释放时机落在请求飞行中也不会泄漏锁静默容错 延迟重试低电量拒绝不弹错、不打扰训练测试模拟器真实复现浏览器丢锁行为保证防线不退化如果你也在做健身类或计时类应用这套 57 行的 Wake Lock 锁屏机制wakelock.js几乎是教科书级的参考实现状态简单、失效路径全被覆盖、测试先行。需要体验完整功能的话可以克隆仓库后按 docker-compose.yml 启动服务git clone https://gitcode.com/GitHub_Trending/op/openGym训练时屏幕常亮从此告别组间解锁的打断。️【免费下载链接】openGymSelf-hosted gym body-weight tracker — plan routines, log workouts (supersets, warm-ups, cardio), see which muscles are trained, fatigued or detrained, import from FitNotes/Strong/Hevy, passkey login. Your data, your server.项目地址: https://gitcode.com/GitHub_Trending/op/openGym创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考