Power down: Improve battery consumption
System & Services 进阶 20m

降低功耗:改善电池消耗

Power down: Improve battery consumption

2022年6月6日

在 Apple 官方观看视频

一句话判断

四个动作——深色模式、审查帧率、限制后台时间、延迟任务——能让你的应用在电池消耗上有肉眼可见的改善。

这场 Session 讲了什么

电池续航是用户体验中最被低估的指标之一。这场 Session 从 Apple 软件功耗团队的实际数据出发,给出了四个可以直接落地的优化方向:

深色模式(Dark Mode):在 OLED 设备(iPhone 13/13 Pro 等)上,深色像素消耗更少的电量。对于大面积背景色较浅的应用,切换到深色模式可以节省最高 70% 的显示功耗。屏幕亮度越高,节省越明显。Session 强调深色模式不只是视觉偏好,更是省电手段。

审查帧率(Audit Frame Rates):在 ProMotion 设备上,屏幕刷新率由当前最高帧率的动画决定。如果主要内容只需要 30fps,但某个次要元素(如滚动文字)在用 60fps 渲染,整个屏幕就会被拉到 60fps。将次要动画降到 30fps 可以节省约 20% 的电池消耗。

限制后台时间(Limit Background Time):后台持续运行的位置服务和音频播放是电池杀手。不需要时要及时调用 stopUpdatingLocation(),使用显著位置变更(significant location changes)替代持续追踪。

延迟任务(Defer Work):用 ProcessInfo.processInfo.performExpiringActivityDispatchQueue.global(qos: .utility) 把非紧急任务推迟到充电时或低优先级队列执行。

值得深挖的点

70% 的显示功耗节省这个数字让人印象深刻。Session 用 Food Truck 应用做演示——它有一个占屏幕大部分面积的背景色。Light Mode 下这个背景是浅色,Dark Mode 下变成深色。在 OLED 屏幕上,这个变化直接反映在每个像素的功耗上。如果你的应用有类似的大面积浅色背景,支持深色模式的省电效果比任何代码优化都来得直接。

**帧率的”木桶效应”**是一个容易被忽视的问题。屏幕刷新率由最高帧率的动画决定,不是平均值。一个角落里的小动画如果以 60fps 运行,即使主内容只需要 30fps,整个屏幕也跑在 60fps。用 Instruments 的 CoreAnimation FPS 工具可以快速发现这种”一颗老鼠屎坏了一锅粥”的情况。

后台位置服务的生命周期管理是另一个常见坑。很多应用在进入后台后忘记停止位置更新,导致 GPS 芯片持续工作。Session 建议在不需要精确定位时切换到 significant location changes 模式,只在区域变化时唤醒。

代码片段

使用 CADisplayLink 控制帧率:

// 创建 display link 并设置期望帧率
let displayLink = CADisplayLink(
    target: self,
    selector: #selector(updateAnimation)
)

// 设置首选帧率范围
// 首选 30fps,最低 10fps,最高 60fps
displayLink.preferredFrameRateRange = CAFrameRateRange(
    minimum: 10,
    maximum: 60,
    preferred: 30
)

// 添加到当前 run loop
displayLink.add(to: .current, forMode: .common)

停止后台位置更新:

// 进入后台时停止精确定位
func applicationDidEnterBackground(_ application: UIApplication) {
    // 不再需要时立即停止
    locationManager.stopUpdatingLocation()
    
    // 如果仍需位置感知,切换到低功耗模式
    locationManager.startMonitoringSignificantLocationChanges()
}

延迟非紧急任务:

// 将非紧急工作放到低优先级队列
DispatchQueue.global(qos: .utility).async {
    // 日志上传、数据预取等非紧急任务
    self.uploadAnalyticsData()
}

// 使用 expiring activity 执行可中断的后台工作
ProcessInfo.processInfo.performExpiringActivity(
    withReason: "数据同步"
) { expired in
    if !expired {
        self.syncPendingData()
    }
}

最佳实践

  • OLED 设备上全面支持深色模式:不只是视觉偏好,是省电策略
  • 用 Instruments 审查帧率:CoreAnimation FPS 工具帮你找到不必要的 60fps 渲染
  • CADisplayLink 设置 preferredFrameRateRange:让系统帮你选择最合适的帧率
  • 后台位置服务及时停止:不用就 stopUpdatingLocation(),不要留在那里”以防万一”
  • 非紧急任务走低优先级队列.utility.background QoS,避免抢占前台资源

还有什么值得关注

  • Safari 的网页内容不会自动变暗,需要在 CSS 中实现 color-scheme 属性
  • Session 建议搭配 WWDC 2019 的 “Implementing Dark Mode on iOS” 和 WWDC 2021 的 “Optimize for variable refresh rate displays” 一起看
  • 热量(thermal load)和电池消耗是联动的——省电也意味着发热减少
  • 对于游戏类应用,60fps 仍然是体验刚需,但 UI 层面的动画可以降到 30fps
WWDC 2022