Tauri + Wake Lock 实战:双端状态机、重获锁与发布一致性
ScreenAwake 最初只想解决一个很小的问题演示、照着教程操作或等待任务时不要让屏幕先熄灭。真正开始实现后我发现“保持常亮”不是一个按钮而是两套不同的系统契约网页只能申请浏览器提供的 Screen Wake Lock桌面端则要持有操作系统级的电源抑制资源。它们可以共用界面却不能共用对生命周期的承诺。这篇复盘不讲“几小时做完一个小工具”只拆四个工程问题用户意图与资源状态为什么要分开、网页锁为何必须重获、桌面端如何确定性清理以及双端发布物怎样避免版本身份漂移。先定义两种产品承诺ScreenAwake 同时提供网页临时模式和 Tauri 桌面模式。两端看起来都只有“开启常亮”背后的约束完全不同。维度网页模式桌面模式核心能力navigator.wakeLock.request(screen)macOScaffeinate、WindowsSetThreadExecutionState、Linuxsystemd-inhibit可见性只有可见、活跃文档能可靠申请主窗口隐藏后仍可由进程持有资源资源句柄WakeLockSentinel可能被浏览器或系统释放子进程或系统电源状态必须由应用主动清理用户预期临时使用标签页需保持可见托盘、倒计时、开机启动、关闭窗口后继续主要失败面浏览器不支持、页面隐藏、低电量或系统策略权限、平台 API、进程残留、退出清理、安装签名MDN 明确说明Screen Wake Lock 只面向可见的活跃文档系统可以因为页面不可见、电量或平台设置释放锁。W3C 草案还把底层获取描述为 advisory-only调用成功不等于应用获得了绕过所有系统策略的保证。所以网页端的产品文案必须是“在支持的浏览器和允许条件下保持屏幕常亮”不能写成“永久阻止休眠”。桌面端能力更强也不能绕过企业 MDM、手动锁屏或组织安全策略。用户意图不等于资源状态网页端最容易写出的实现是拿state.active同时表示两件事用户想继续保持常亮以及当前 Wake Lock 仍然有效。问题是浏览器释放锁时active会变成false当标签页再次可见程序已经不知道用户是主动点了“停止”还是资源被系统暂时收走。ScreenAwake 后来把这两个状态拆开letwebWakeLock:WakeLockSentinel|undefined;letwebKeepAwakeRequestedfalse;asyncfunctionstart(){webKeepAwakeRequestedtrue;webWakeLockawaitnavigator.wakeLock.request(screen);}asyncfunctionstop(){webKeepAwakeRequestedfalse;awaitwebWakeLock?.release();webWakeLockundefined;}webKeepAwakeRequested是用户意图webWakeLock是当前资源句柄。前者只有用户操作才能取消后者可以被浏览器、系统或代码释放。这个拆分不只适用于 Wake Lock。WebSocket、麦克风流、蓝牙连接、文件句柄和长任务也应该区分“用户仍然需要”与“资源此刻可用”。否则一次短暂断开就会被误判为用户取消。被释放的 Sentinel 不能复用WakeLockSentinel被释放后不能重新激活如果用户意图仍然存在应用必须申请一个新对象。ScreenAwake 在release事件中先确认回调对应的仍是当前句柄再清理状态页面重新可见时只在用户仍有意图且句柄不存在或已释放时重获锁acquiredWakeLock.addEventListener(release,(){if(webWakeLockacquiredWakeLock)webWakeLockundefined;state.activefalse;state.powerGuardActivefalse;render();});document.addEventListener(visibilitychange,(){constshouldReacquiredocument.visibilityStatevisiblewebKeepAwakeRequested(!webWakeLock||webWakeLock.released);if(shouldReacquire)voidstart();});这里保留acquiredWakeLock局部引用是为了防止旧对象的延迟release事件把新句柄清掉。它和网络请求里的 request ID、搜索建议里的 sequence number 是同一类并发防线旧事件不能覆盖新状态。桌面端先持有主资源再叠加可选兜底桌面端没有把鼠标微动当成主方案。主路径是操作系统电源抑制锁macOS 启动caffeinate -d -iWindows 调用SetThreadExecutionStateLinux 启动systemd-inhibit。鼠标微动、Shift 短按和隐藏窗口 ping 都是可选策略。鼠标微动在 macOS 上还要先检查辅助功能权限键盘兜底默认关闭。这个顺序很重要能用系统提供的电源 API就不应先模拟用户输入。桌面状态机每次开始前先停止旧控制器再创建新资源和截止时间pubfnstart(self,options:AwakeOptions)-ResultAppStatus,String{self.stop();letmutcontrollerself.controller.lock().map_err(|_|状态锁不可用.to_string())?;controller.power_guardSome(PowerGuard::start()?);controller.deadlineoptions.duration_seconds.filter(|seconds|*seconds0).map(|seconds|Instant::now()Duration::from_secs(seconds));Ok(Self::status_locked(controller))}start()先调用stop()可以避免重复点击后残留两份caffeinate子进程、输入线程或倒计时。停止时再依次翻转原子标志、结束输入线程、停止窗口 ping、释放电源锁并清空截止时间。这是一条适合小工具的简单不变量任意时刻最多只有一组持有资源的控制器。关闭窗口不等于停止任务桌面端另一个容易混淆的状态是“窗口关闭”和“应用退出”。ScreenAwake 拦截主窗口关闭把窗口隐藏到托盘只有托盘退出或进程退出时才停止电源防护。.on_window_event(|window,event|{iflettauri::WindowEvent::CloseRequested{api,..}event{api.prevent_close();let_window.hide();}}).run(|app,event|{ifletRunEvent::ExitRequested{..}event{app.state::AppState().stop();}});如果产品把“关窗口”定义成“停止常亮”就不该隐藏到托盘如果定义成后台继续界面必须明确提示托盘也必须提供停止和退出入口。生命周期不是框架默认行为而是产品契约。双端发布要记录两种构建身份ScreenAwake 的网页端在main推送后自动部署 GitHub Pages桌面端则在v*标签上构建 Release。两条流水线本身没有问题但它们会让“当前版本”出现两种身份。本次核验时发布面核验身份结果GitHub Pages /main1802fa2922ac1ddaebb748b9649f9636cdbaae10包含返回可见时重获 Wake Lock 的修复桌面 Releasev0.1.2b6e5e8f7c8e6291553e9656cc8ed27f13c661cc4早于上述网页修复package.json/ Tauri 配置0.1.2两端仍显示同一语义版本号这意味着“版本号都是 0.1.2”不能证明网页与桌面包含同一提交。更稳妥的做法是让两个界面显示version short commit发布记录同时保存 Pages 提交、Release tag 和资产校验值。最小检查可以写成gitrev-parse HEADgitrev-parsev0.1.2^{commit}gitlog--onelinev0.1.2..HEAD如果网页修复也应该进入桌面包就应发布新 tag如果只影响网页也要在发布记录中明确两个分发面的能力差异。本次验证通过了什么我在 2026-08-02 对公开仓库和页面做了重新核验npm ci成功npm run build成功Vite 生产构建生成distcargo check --manifest-path src-tauri/Cargo.toml成功cargo test --manifest-path src-tauri/Cargo.toml命令成功但实际运行0 个单元测试、0 个文档测试Ego 真实浏览器打开公开网页页面标题、四档时长和navigator.wakeLock支持回读正常GitHub Releases 公开页显示v0.1.2为 Latest并能追溯到 tag 提交源码共 9 个主要前后端文件仓库内未发现 JavaScript / TypeScript 测试文件或 Rust#[test]。所以当前能说的是“源码可以完成前端生产构建和本机 Rust 静态检查”不能说“桌面端已被自动化测试覆盖”也不能说 Windows x64、macOS ARM64、托盘、开机启动、快捷键、倒计时和退出清理都已经完成本轮端到端回归。下一版最该补的三道门第一道是状态机测试。至少覆盖用户主动停止、页面隐藏自动释放、返回可见重获、旧 Sentinel 延迟事件、重复开始、倒计时到期和退出清理。第二道是发布物身份。网页和桌面都显示提交短 SHARelease 记录资产 SHA-256面向 macOS 公开分发前补齐 Developer ID 签名和公证而不是把临时签名写成完整分发能力。第三道是真机矩阵。网页端验证支持与不支持 Wake Lock 的浏览器、页面切后台、低电量和手动锁屏桌面端分别在 macOS ARM64、Windows x64 和计划支持的 Linux 环境验证系统 API 与退出清理。可复用检查表用户意图与当前资源句柄分开保存资源被系统释放时不误判为用户取消旧资源的延迟事件不能覆盖新资源重获资源前重新检查可见性、权限和系统条件重复开始前确定性停止上一组资源关闭窗口、停止任务和退出应用有明确区分主能力优先使用平台 API模拟输入只做可选兜底网页部署提交与桌面 Release tag 分别记录“测试命令成功”与“实际测试数量”分开报告未签名、公证、真机回归的能力不写成已完成。小工具真正难的地方通常不是把按钮点亮而是把“用户还想要什么”“系统现在给了什么”“资源何时必须收回”三件事分清楚。生命周期和发布身份一旦清楚网页与桌面才能共享产品体验而不是共享一组含糊承诺。来源与验证边界ScreenAwake 仓库网页端实现核验提交桌面状态机核验提交系统电源防护实现核验提交GitHub ReleasesMDN Screen Wake Lock APIW3C Screen Wake Lock 工作草案验证边界本文验证了公开网页、源码提交、前端生产构建、本机 Rustcheck与 Release 身份没有执行 Windows / macOS 安装包真机端到端回归也没有把cargo test的 0 个测试写成测试覆盖。

相关新闻

逻辑回归实战:从乳腺癌数据集到完整机器学习工作流

逻辑回归实战:从乳腺癌数据集到完整机器学习工作流

1. 项目概述:从数据到诊断的逻辑回归之旅 在机器学习的入门与实战领域,有一个数据集的地位堪比“Hello World”,那就是威斯康星州乳腺癌诊断数据集。它不像鸢尾花数据集那样简单,也不像MNIST那样庞大,但它完美地融合了…

2026/10/12 12:06:42 阅读更多 →
Python多线程编程:从基础到高级应用

Python多线程编程:从基础到高级应用

1. Python线程基础概念解析 在Python编程中,线程是最小的执行单元,也是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。理解线程对于编写高效、响应迅速的Python程序至关重要。 Python标准库中的 thread…

2026/10/9 22:49:54 阅读更多 →
虚拟电厂随机优化调度:蒙特卡洛与CPLEX实战

虚拟电厂随机优化调度:蒙特卡洛与CPLEX实战

1. 项目概述:虚拟电厂与随机优化调度虚拟电厂(Virtual Power Plant, VPP)作为能源互联网的核心技术之一,通过聚合分布式能源资源(DERs)实现与传统电厂等效的调度功能。这个MATLAB项目针对源(发电…

2026/10/11 4:13:59 阅读更多 →

最新新闻

Sufer 8.0英文版等值线图实战:从散点插值到批量出图的完整避坑指南

Sufer 8.0英文版等值线图实战:从散点插值到批量出图的完整避坑指南

简介:Surfer 8.0英文版是Golden Software公司推出的专业地形图绘制与三维建模软件,面向地质、环境科学、工程及地球科学领域的从业者与学习者,用于将离散数据转化为连续格网表面并生成专业图件。压缩包共234个文件,约12.41MB&…

2026/10/13 20:10:07 阅读更多 →
校园外卖系统数据库课设实战:三端闭环与状态机设计

校园外卖系统数据库课设实战:三端闭环与状态机设计

简介:本资源是一套完整的微信小程序校园外卖系统课程设计实践项目,面向高校数据库原理与应用、Web前端开发及小程序实战类课程的学生与教师,解决课程设计中缺乏真实业务场景、前后端协同与数据库建模结合案例的问题。压缩包共123个文件&#…

2026/10/13 20:10:07 阅读更多 →
二值图中心线提取实战:从细化算法到毛刺修剪与亚像素优化

二值图中心线提取实战:从细化算法到毛刺修剪与亚像素优化

做图像处理开发的朋友,十有八九都碰到过这类需求:从一张二值图里,把细长目标的中心线稳定地提出来。PCB走线、打印字符的笔画中心、纤维或者线缆的轴线,甚至医学影像里的血管路径,本质上都是同一个问题。最直觉的方案是…

2026/10/13 20:10:07 阅读更多 →
布匹瑕疵数据集-2019天池:工业表面检测小目标与低对比度缺陷基准

布匹瑕疵数据集-2019天池:工业表面检测小目标与低对比度缺陷基准

简介:本资源为2019年天池平台发布的布匹表面瑕疵检测专项数据集,面向计算机视觉方向的初学者与工业质检算法研究者,适用于缺陷识别、目标检测模型训练与小样本学习等实践场景。压缩包共935个文件,含689张JPG格式布匹瑕疵图像&…

2026/10/13 20:10:07 阅读更多 →
STM32F407ZG智能门锁实战:矩阵键盘+OLED+蓝牙+舵机全链路实现

STM32F407ZG智能门锁实战:矩阵键盘+OLED+蓝牙+舵机全链路实现

简介:本资源是一套基于STM32F407ZGT6的智能门锁完整嵌入式开发项目,面向电子/自动化/物联网方向本科生及毕业设计学生,聚焦密码验证、本地交互与蓝牙远程控制三大核心功能,切实解决毕业设计中硬件选型、多外设协同与系统集成等典型…

2026/10/13 20:10:07 阅读更多 →
PS5串流实战指南:从局域网到外网的远程游戏配置与延迟优化

PS5串流实战指南:从局域网到外网的远程游戏配置与延迟优化

直接接PS5玩家一个很现实的问题:这台机器买回来之后,是不是基本就长在客厅电视柜上了?客厅被占、卧室想玩、出差想刷两把,每次都只能乖乖回到电视前。我捣鼓AnyPS5这套串流方案,就是为了把这台主机从HDMI线的长度里解放…

2026/10/13 20:09:06 阅读更多 →

日新闻

物联网系统集成避坑指南:从选型到验收的关键要点

物联网系统集成避坑指南:从选型到验收的关键要点

做了这么多年物联网系统集成的项目,我最大的感受是,大部分坑不是出在技术前沿,而是出在一些看起来很平常的地方。设备选了便宜的、协议没问清楚、现场没摸透、验收标准写得含糊——这些细枝末节,最后都会变成延期、超支和扯皮的大…

2026/10/13 0:00:57 阅读更多 →
ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

如果你玩ESP32有一阵子了,很难不碰到舵机控制这道坎。做智能小车要转方向,做机械臂要抬关节,做云台要偏航俯仰,背后都是同一个东西在干活:舵机。而我见过太多人卡在“代码能编译、舵机就是不听话”这个阶段&#xff0c…

2026/10/13 0:00:57 阅读更多 →
CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

1. 为什么CAN总线至今仍是工业现场的“硬通货”?——从汽车底盘到智能温室的真实需求你有没有拆过一辆老款燃油车的中控台?或者调试过某高校实验室里那台跑着Modbus协议却频频丢帧的PLC控制柜?又或者,在某个农业物联网项目里&…

2026/10/13 0:00:57 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/13 2:54:56 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/13 16:22:04 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/13 1:58:08 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 21:05:09 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 14:57:39 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 18:11:17 阅读更多 →