Screen wake lock requires battery-conscious strategies, not just always-on screens
How to responsibly keep screens on in PWAs without draining battery excessively.
为什么屏幕唤醒锁对 PWA 很重要
默认情况下,设备会在一段时间后关闭屏幕以延长电池寿命。这虽然有用,但某些应用需要屏幕保持开启才能发挥最大效用。
屏幕唤醒锁(Screen Wake Lock)API 防止屏幕关闭、变暗或锁定,提供简单的基于平台的解决方案。
典型用例:
- 电子书阅读:防止翻页时屏幕突然变暗
- 地图导航:保持路线可见,不要锁屏干扰导航
- 菜谱/教程:避免操作中途屏幕熄灭
- 演示/演讲:演示时保持屏幕常亮
- QR/条码扫描:确保相机持续预览
- 语音/手势控制:无需触控输入时保持屏幕活跃
MDN 文档指出,唤醒锁请求可能因多种原因拒绝,包括系统设置(省电模式、低电量)或文档不活跃/不可见。
如何实施屏幕唤醒锁
步骤 1:功能检测
检查浏览器是否支持:
if ('wakeLock' in navigator) {
console.log('Screen Wake Lock API supported');
// 启用相关 UI 控件
enableWakeLockButton();
} else {
console.log('Wake Lock not supported');
// 禁用或隐藏相关功能
wakeLockButton.disabled = true;
}步骤 2:请求唤醒锁
使用 navigator.wakeLock.request('screen') 异步请求:
let wakeLock = null;
async function requestWakeLock() {
try {
wakeLock = await navigator.wakeLock.request('screen');
console.log('Wake Lock is active!');
updateUI('Wake Lock Active');
// 监听自动释放事件
wakeLock.addEventListener('release', () => {
console.log('Wake Lock released');
wakeLock = null;
updateUI('Wake Lock Inactive');
});
} catch (err) {
console.error(`${err.name}, ${err.message}`);
// 处理失败(如低电量、省电模式)
showErrorMessage('Wake Lock request failed');
}
}关键 API:
navigator.wakeLock.request('screen'):请求屏幕唤醒锁WakeLockSentinel:返回的对象,代表底层系统唤醒锁wakeLock.release():手动释放唤醒锁wakeLock.addEventListener('release', callback):监听自动释放事件
步骤 3:处理文档可见性变化
当文档变得不可见时(如切换标签页),唤醒锁会自动释放。文档重新可见时需要重新请求:
let autoReacquire = false; // 用户可配置
document.addEventListener('visibilitychange', async () => {
if (wakeLock === null && document.visibilityState === 'visible' && autoReacquire) {
try {
wakeLock = await navigator.wakeLock.request('screen');
updateUI('Wake Lock Reacquired');
} catch (err) {
console.error('Failed to reacquire wake lock:', err);
}
}
// 如果文档变得不可见,wakeLock 可能已被系统自动释放
if (document.visibilityState !== 'visible' && wakeLock !== null) {
updateUI('Wake Lock Will Release');
}
});步骤 4:手动释放唤醒锁
用户主动结束需要常亮屏幕的活动时,应立即释放:
function releaseWakeLock() {
if (wakeLock) {
wakeLock.release()
.then(() => {
wakeLock = null;
updateUI('Wake Lock Released');
})
.catch((err) => {
console.error('Error releasing wake lock:', err);
});
}
}
// 为用户提供释放按钮
releaseButton.addEventListener('click', releaseWakeLock);性能和电池优化策略
何时使用唤醒锁
MDN 文档提供了明确指导:
- 票据应用:显示 QR 码时请求唤醒锁,扫描完成后立即释放
- 演示应用:仅在演示活跃时保持唤醒锁,编辑时不应请求
推荐模式:仅在需要时请求唤醒锁,并在活动结束时立即释放。
不应使用唤醒锁的场景
| 场景 | 原因 | 替代方案 | |------|------|----------| | 长时间下载 | 唤醒锁耗电 | ✅ Background Fetch / Periodic Background Sync | | 数据同步 | 不需要屏幕 | ✅ Background Sync | | 后台音乐播放 | 屏幕无需常亮 | ✅ Media Session API(设备支持后台播放) | | 社交 IM 消息应用 | 不需要常亮 | ✅ Push Notifications 提醒用户 |
电池意识最佳实践
- 监听电池状态(如果浏览器支持
navigator.getBattery()):
if ('getBattery' in navigator) {
navigator.getBattery().then((battery) => {
// 低电量时避免请求唤醒锁
if (battery.level < 0.2 && !battery.charging) {
return;
}
requestWakeLock();
});
}- 监听充电状态变化:
battery.addEventListener('chargingchange', () => {
if (battery.charging) {
requestWakeLock(); // 充电时可请求
} else {
releaseWakeLock(); // 停止充电且电量低时释放
}
});- 检测浏览器是否处于省电模式(如果 API 可用) - 提示用户是否允许保持屏幕常亮
- 避免在省电模式下请求唤醒锁:
安全性和权限
Permissions Policy 控制访问
MDN 文档指出,访问 Screen Wake Lock API 由 Permissions-Policy 头控制:
Permissions-Policy: screen-wake-lock=(self)默认行为(self):
- ✅ 同源嵌套 frame 可使用唤醒锁
- ❌ 第三方内容阻止使用刷新锁
允许特定第三方:
Permissions-Policy: screen-wake-lock=(self "https://b.example.com")然后在 iframe 中添加 allow 属性:
<iframe src="https://b.example.com" allow="screen-wake-lock"></iframe>系统级限制
浏览器可能因特定原因在文档中阻止屏幕锁定:
- 用户设置(如"永不锁定屏幕"被禁用)
- 平台限制(如省电模式)
- 低电量警告
用户通知:浏览器应提供不显眼的机制通知用户唤醒锁处于活动状态,并提供用户移除应用屏幕锁的能力。
实施检查清单
在产品化前:
技术实现
- [ ] 功能检测(navigator.wakeLock)
- [ ] 异步错误处理(低电量、省电模式、文档不活跃)
- [ ] 监听
release事件以处理自动释放 - [ ] 处理
visibilitychange事件重新请求唤醒锁(可选)
用户体验
- [ ] 清晰的 UI 状态指示("屏幕常亮已开启"/"屏幕常亮已关闭")
- [ ] 提供用户手动释放唤醒锁的按钮/开关
- [ ] 活动结束后自动释放唤醒锁(如计时器、任务完成)
- [ ] 提供禁用/偏好设置(用户可完全关闭此功能)
性能和电池
- [ ] 避免长时间持有唤醒锁(如背景播放视频)
- [ ] 结合电池状态 API 优化唤醒锁请求时机
- [ ] 提供收集电池使用量反馈的机制
- [ ] 文档说明唤醒锁对电池续航的影响
对开发者意味着什么
产品机会
- 阅读/导航类 PWA:提供流畅的沉浸体验,无屏幕关闭干扰
- 教育/教程应用:确保学生在操作教程时不会因锁屏分心
- 演示/会议应用:演讲者无需担心设备突然锁屏
技术债务
- 调试困难:唤醒锁效果在真实设备上才能触发,开发者工具模拟效果有限
- 跨平台差异:不同浏览器/操作系统对唤醒锁处理可能不同
- 状态管理复杂度:需要正确处理唤醒锁获取、释放、自动释放、重新请求的生命周期
用户体验风险
- 电量焦虑:用户可能担心唤醒锁会快速耗电
- 误解用途:用户可能不理解为何需要"保持屏幕常亮"
- 控制权:用户可能无法觉察唤醒锁处于活动状态
决策框架
| 场景 | 使用唤醒锁 | 不使用唤醒锁 / 替代方案 | |------|------------|-----------------------| | 电子书阅读 | ✅ 提升阅读体验 | ⚠️ 改为自动翻页但允许锁屏 | | GPS 导航 | ✅ 保持路线可见 | ⚠️ 使用后台 Geolocation 音频提示 | | QR 码扫描 | ✅ 确保相机持续预览 | ⚠️ 改用短暂的闪光引导 | | 在线课程播放 | ⚠️ 视频内容锁屏不影响播放 | ✅ 允许屏幕关闭,后台播放 | | 音频播客 | ❌ 视频无需常亮 | ✅ 完全依赖 Media Session API | | 社交 IM | ❌ 无需常亮 | ✅ Push Notifications 提醒 | | 游戏活动 | ⚠️ 可选性功能 | ⚠️ 提供设置禁用唤醒锁 |
下一步
- 需求审查:确定你的应用场景真的需要常亮屏幕,而非通过其他方式(如音频、通知)满足需求
- 原型测试:在真实设备上体验唤醒锁效果,评估电池影响
- 用户反馈:收集用户对"屏幕常亮"功能的反馈,调整产品策略
- 性能监控:在应用 中添加电池使用量监控和用户报告机制
屏幕唤醒锁是提升用户体验的有力工具,但必须负责任地使用。仅在必要时请求,并在活动结束时立即释放,才是平衡电池续航和用户体验的最佳实践。