大多数浏览器和
Developer App 均支持流媒体播放。
-
控制电量:优化电池电量消耗
了解如何限制电量消耗,帮助用户更充分地利用您的 App。我们将介绍如何通过对您的代码执行四项关键更改,降低 App 的电池电量消耗。学习如何为您的 App 添加深色模式并利用 OLED 显示屏的优点,审核辅助动画的帧率,限制后台数据处理,以及推迟长时间运行的任务。
资源
相关视频
WWDC22
WWDC21
WWDC19
-
下载
♪ ♪ Vaibhav Gautam: 大家好 我是 Vaibhav Gautam 我是 Software Power 团队的 工程师 App 为人们的日常生活 提供了多种多样的重要功能 让生活更丰富多彩 但这些功能需要付出一定代价 即电量消耗 因此 如何改进 App 的 耗电量 让用户有更长的时间 使用设备和您的 App 是需要格外关注的问题 我们深入研究了不同的系统组件 了解电量消耗的问题 有四个关键行动 可以大大改善您 App 的耗电量 在本次讲座中 我们将与大家逐一分享 其中包括 App 的深色模式 审计帧率 限制后台时间 以及推迟 App 的任务
首先 我们先看下深色模式 深色模式在 iOS 13 中 首次推出 用户可将设备配置为 深颜色的显示方式 深色模式的个性化显示 您应该不陌生 但这对耗电量同样有 极大的影响
这是因为在使用 OLED 显示屏的设备中 如 iPhone 13 和 13 Pro 深色内容比浅色内容 耗电量更低 在 OLED 显示屏中 每个像素都需要单独的能耗 而深色模式下 点亮像素所需的 能耗较少 系统的所有组件中 显示屏是耗电最多的 实际上 在典型用例中 显示屏是电池损耗的 主要来源 您可以改变显示屏的电池损耗 其中一个方法就是应用深色模式 我以我们团队正在开发的 Food Truck App 为例 这一 App 的背景颜色很显眼 占据了显示屏的大部分 使用深色模式时 背景颜色比浅色模式下的深 大大减少了电池损耗 事实上 在这种案例中 我们预期 电池损耗能减少 70% 以上 这是非常惊人的比例 屏幕亮度高 电池电量节省更多 对喜欢用深色模式的用户来说 这是减少耗电的绝佳机会 同时也可以减少热负荷 要应用深色模式 首先要看下 您的 App 当前在 深色模式下是如何显示的 想想如果要适应系统 UI 需要更新您 App 中哪些组件 而 Xcode 构建 App 时使用外观功能 让这一过程更简便
您的 App 如果仅支持浅色模式 可能会使用硬编码颜色 在 Xcode 中使用动态颜色 以支持浅色和深色模式中的 背景颜色 图像和文本 系统会自动应用正确的色值 根据模式改变进行更新
您的 App 应同样支持 浅色和深色模式中的 替代图像 您可查看 WWDC 2019 中的 “Implementing Dark Mode on iOS” 以了解更多关于自定义 App 深色模式的信息
现在您知道如何在 App 中 应用深色模式了 网页内容中如何应用深色模式 同样也是需要考虑的 Safari 不会自动加深 网页内容颜色 因此要确保您的网页内容 也能适应深色模式
要在您网站的样式表中 实现配色方案属性
在网页中启用默认文本及背景颜色 从而匹配当前系统外观 标准表单控件和滚动条 其它指定的系统颜色 会改变外观 在浅色和深色模式之间转换 无论颜色在样式表中 哪个位置被引用 都请使用样式表变量 这让您的网页内容 可以随着设备在浅色模式 和深色模式之间的切换 更新其颜色 将同样的逻辑应用到 网页的图像及其它媒体 assets 中 为不同模式套用不同变体 您可查看 WWDC 2019 中的 “Supporting Dark Mode in Your Web Content” 以了解更多关于在网页内容中 应用深色模式的内容 另一个减少 App 电池损耗的方法 是审计帧率 在使用 ProMotion 显示屏的设备中 刷新率会影响电池损耗 高刷新率则需要高能耗 您 App 中的动画帧率 决定了显示屏的刷新率 想想 App 的主要内容 以及需求的帧率 不一定 App 中的所有内容 都需要高帧率 显示屏的刷新率是由您 App 中 最高帧率的动画决定的 您的 App 可能有次要元素的 刷新率 高于必要水平 导致 App 整体消耗比预期 更多的电量
我们再以 food truck App 为例 顶部主要的卡车场景 是以每秒 30 帧的速率渲染的 在卡车下面 有一个文字蒙版 “Food Truck” 以水平方向滚动 这种次要文本是以 每秒 60 帧的速率渲染的 结果是 整个屏幕现在均以 每秒 60 帧的刷新率渲染 如果我们将文本动画 改为 30fps 整个屏幕就以 30fps 来渲染 我们可以减少高达 20% 的 电池损耗 太神奇了 要调试和获取更多关于 您 App 帧率的信息 就使用 Instruments 吧 使用 instrument 中的 CoreAnimation FPS 可以查看您 App 随着时间推移的 帧率时间线 首先审计主要用户场景 确定帧是否以预期的帧率渲染 确定屏幕上的次要元素帧率 是否高于主要内容的帧率
您的 App 可能使用 iOS 中的 CoreAnimation 所提供的 CADisplayLink 来驱动自定义动画 以及自定义渲染循环 CADisplayLink 是一个定时器 与显示屏刷新率同步 它为您 App 提供了 必要的计时信息 这样您的自定义绘图 能意识到刷新率 您的 App 可提示 CADisplayLink 对象 期望的屏幕刷新率是什么 设置 CADisplayLink 的 preferredFrameRateRange 指定您最小 最大和偏好帧率
Display link 随后根据 系统能处理的范围 选择可用帧率中 与您偏好帧率最接近的数值 如果无法提供该数值 则会尝试保留在您指定的范围内 要配置您的 display link 用 target 和 selector 初始化 提供的 selector 用于 运行自定义动画 计算下一次显示的视频帧 初始化 display link 后 设置偏好帧率范围 在这一例子中 偏好帧率为 30 但范围可在 10 至 60 之间 最后 在当前运行循环中 添加 display link
当考虑 App 的电池损耗时 要紧记刷新率 这对于使用 ProMotion 显示屏 支持高动态刷新率的 设备来说尤为重要 使用 Instruments 监测 您 App 的帧率 在发布 App 前先发现问题 最后 将信息提供给系统 用 CADisplayLink 限制 App 内容的刷新率
您可查看 WWDC 2021 的 “Optimize for variable refresh rate displays” 以了解更多 关于帧率优化的信息 现在 我们来说下 App 后台运行时 如何减少电池损耗 当有人将您的 App 切换到另一个 App 时 您的 App 可能会需要使用 后台执行 APIs 来保证在后台持续运行 在后台运行时 您的 App 可能会继续使用 常用服务 如定位和音频 长时间运行这些服务 将会导致电池损耗 因此 当您的 App 在后台 使用这些服务时 您需要尤为小心 我们来说下使用这些模式时 如何避免过多的电池损耗 定位服务保证设备处于唤醒状态 从而持续定位 即使对于用户来说 App 并不可见 也可能在后台持续进行 定位的流式传输 导致电池损耗过多 很重要的是 要确保您清楚了解 您 App 后台定位 session 的 运行时间 当您不需要该 session 时 确保 App 调用 stopUpdatingLocation() 从而停止该 session 在 App 开发的不同阶段 您可以用不同的工具 来查看后台定位使用 可能会超乎您所料 在构建和测试 App 时 Xcode gauges 可用于 查看系统能耗 以及后台定位使用 发布前测试 App 时 您可以使用 MetricKit 来收集 一天内使用情况的诊断信息 iOS 16 中新增了 在 Control Center 显示定位使用 Xcode gauges 提供关于 系统使用的信息 如 CPU 网络 定位使用 Xcode gauges 会展示 您 App 的定位使用 以及能量损耗时间线 这一时间线视图可验证您的 定位运行时间是否在您 预期的时间停止 这是一个绝佳的方法 另一个工具是在测试 App 时 使用 MetricKit 使用 cumulativeBackgroundLocationTime 属性 查看您 App 在后台 使用定位服务的活跃时间
在 iOS 16 的更新中 用户可以通过 浏览 Control Center 监测当前使用定位服务的 App 用户可以点击顶部的文本 查看使用定位的 App 的详细视图 用这种方式可以发现那些 不在前台运行 却仍然在使用定位系统的情况 如果您的 App 毫无征兆地 在这里显示 就是您 App 有活跃定位流 session 的指标 我们可以将同样的原则 应用到音频 sessions 假设我们有一个音乐 App 使用音频播放器 来回放一些文件 而用户停止了回放 App 不仅应暂停或停止音频 而且应暂停或停止 Audio Engine 从而阻止其空运转 我们推荐使用自动关闭模式 该模式可通过设置 AVAudioEngine 类的 autoShutdownEnabled 来启用 在这一模式下 audio engine 继续监控及探测 在一定期间内是否空运转 如在空运转 引擎将关闭音频硬件 随后 如果有任何软件源 再次活跃运行 将会动态开启音频硬件 这些都是在后台运行的 watchOS 的自动关闭模式是 强制执行的行为 确保在 Audio Engine 未使用时 将其停止 从而减少能耗 限制后台运行时间的关键在于 要记得提示系统您完成的时间 最后一个改善耗电量的动作 是延迟工作 在一天的使用中 您的 App 可能要处理 许多不同的任务和数据 有些是需要在服务用户操作时 立即进行的 如屏幕上的渲染内容 或用户点击时播放音频或视频
其它运行工作如机器学习任务 上传分析或备份 时间敏感性并不高 如果我们将这些非时间敏感性的工作 延迟到其它更合适的时间 在设备充电时 我们可以节省电池损耗 避免与用户主动触发的 及交互性工作发生冲突 我们来看下您可以用来完成 该行为的三个 APIs BGProcessingTask 是延迟 长时间运行工作的绝佳选择 授权系统支配的 URLSession 是规划可延迟网络连接的 完美选择 利用正确的推送优先级 可帮助服务器 在适宜的时间传递推送 我们逐一详细了解下 首先是 BGProcessingTask BGProcessingTask 可让您 将长时间运行的处理任务 延迟到其它更适宜的时间 如设备充电时 这对如数据库清理 创建备份 运行机器学习训练 诸如此类的任务非常适合 您只需通过使用 BGProcessingTaskRequest API 创建请求 提供一个应用标识符 然后提供更多信息 如您的任务是否需要 外接电源或网络 提供更多信息可帮助系统 在更好的时间窗口内 规划该任务 系统会在合适的时间 后台启动您的 App 保证数分钟的运行时间 从而完成可延迟工作 接下来是 discretionary URLSession 您的 App 可能已经在普通网络连接中 使用了 Background URLSessions 在您使用 discretionary 标记时 Background URLSessions 将更为理想 有 discretionary 标记的 URLSessions 将完全由系统决定 在更优时间运行网络连接任务 如当设备接通电源 和连接至 Wi-Fi 时 discretionary 标记非常适用于 非用户触发的 长时间运行的网络 如远端信息收集 或下载电视剧集的下一集 由于网络任务是全权交给系统的 意味着您的 App 不需要 在网络事务完成时运行 要使用 discretionary URL sessions 您只需设置一个 background URL session 将 isDiscretionary 设置为 true 您可提供额外信息 帮助系统在合适的时间计划下载 设置超时间隔 这样系统不会一直尝试下载 从而导致电池损耗
如果您未来一段时间内 不想上传或下载数据 可以设置最早开始的时间 最后 设置预期的工作量大小 这样系统可智能地 在您多个下载任务中 保持负载平衡
与您用 BGProcessingTask 和 discretionary URL sessions 控制某些操作的即时性类似 您可以通过使用 不同的推送优先级 影响推动的即时性 推送优先级决定了一个通知 推送到设备的 紧急性 对于高优先级的推送 服务器会将其立即推送到设备 潜在地唤醒设备 导致电池损耗 对于低优先级的推送 服务器会将其延迟 直至更为恰当的时机再予以推送 如设备唤醒时 或者有高优先级推送出现时 高优先级推送是如重大天气预警 这种紧急信息的最好选择 低优先级推送适用于 更被动的通知 不紧急且可以被延迟的 利用低优先级推送 推迟可延迟信息的推送 将减少电池损耗 因为设备 不会频繁地从休眠中被唤醒 要配置低优先级推送 只要在推送负载中 将 apns-priority 设置到 5 服务器会处理余下的部分 您的用户会为电量节省而满意 我们来总结下最后的想法 和接下来的步骤 在你的 App 中 提供深色模式的选项 如果用户选择深色模式 尊重其选择可减少电池损耗 查看您的动画 寻找机会在必要时降低帧率 一个小动画都可能带来大改变 让系统知道您已完成动作 时刻关注您的后台运行时间 最后 考虑延迟 长时间运行的后台工作 至其它更好的时机 如设备连接电源时 如果您完成了这些操作 就会真正降低您 App 的能耗 感谢大家
-
-
8:02 - Create a CADisplayLink
// Create a display link func createDisplayLink() { let displayLink = CADisplayLink(target: self, selector: #selector(step)) // Configure your desired refresh rate by calling preferredFrameRateRange displayLink.preferredFrameRateRange = CAFrameRateRange(minimum: 10, maximum: 60, preferred: 30) // then activate your CADisplayLink by adding it to the main runloop. displayLink.add(to: .current, forMode: .defaultRunLoopMode) }
-
16:03 - Discretionary URLSession
// Set up background URL session let config = URLSessionConfiguration.background(withIdentifier: "com.app.attachments") let session = URLSession(configuration: config, delegate: ..., delegateQueue: ...) // Set discretionary config.isDiscretionary = true // Set timeout intervals config.timeoutIntervalForResource = 24 * 60 * 60 config.timeoutIntervalForRequest = 60 // Create request and task var request = URLRequest(url: url) request.addValue("...", forHTTPHeaderField: "...") let task = session.downloadTask(with: request) // Set time window of two hours task.earliestBeginDate = Date(timeIntervalSinceNow: 2 * 60 * 60) // Set workload size task.countOfBytesClientExpectsToSend = 160 task.countOfBytesClientExpectsToReceive = 4096 task.resume()
-
-
正在查找特定内容?在上方输入一个主题,就能直接跳转到相应的精彩内容。
提交你查询的内容时出现错误。请检查互联网连接,然后再试一次。