链接是wwdc 2019的视频,内容是关于App后台的改进。演讲分两部分内容:
- 后台任务的核心关注点是电源、性能和隐私
- iOS13提供了一套新的Api用于执行可延迟的后台任务,关于后台任务请按需操作
整个看下来并没有我特别关心的蓝牙后台模式,不知道蓝牙后台这块有没有很大的变化。毕竟我的理解能力有限,也可能是我没有读懂官方意图,还请指正。另外建议还是看一下原视频,如果网络问题看不到的话至少读一下文字内容。
以下是字幕材料的中文翻译(开发者App上可见,不是我翻译的,我只是搬运一下):
我是Roberto 来自Apple的软件电量团队 今天能来到这里 我感到万分激动 我要与大家分享 关于App后台执行的改进 (关于APP后台执行的改进) 用户们喜欢用app 他们喜欢用app的原因是因为 app为他们提供许多很优秀的体验 有些是在前台 当用户积极地使用app时 而有些是在后台 要求后台执行才能实现 如果我们提出可能需要后台执行的 一个列表 我们可能会提出类似这样的东西 比如导航或配件通讯 或也许是定期更新和下载 在Apple我们设计了 提供后台执行的API 用于处理这些用例和提供此类体验
今天我们要讲的是后台执行 先概述一下 然后接着讲一些最佳实践 最后我同事Thomas会上台来 介绍一个新的后台任务框架 提供新的后台执行的机会
让我们先简单了解一下后台执行 (后台执行概述) 我们可以先回答这个问题 什么是后台执行? 我们是指什么? 当我们提到后台时 我们可以指很多东西 后台线程或后台队列 但当我们讲后台执行时 我们指的是当app不处于前台时 运行我们的执行代码 请看这个图表 我们指的是第三个方框 app在后台运行 但用户不一定能看到它运行
我们为什么要进入这种状态呢? 这可以归结为两种途径 第一种是app发出请求 这应用于更通用的后台执行 当app想实施一些工作时 它可以向系统发出请求 你可以思考一下 比如说下载或定期更新 或也许是完成一些后台工作
第二种是通过特定的事件触发器 app获得后台时间 以响应某件事 比如也许用户去了国外 或也许有一些新的健康数据 App需要引起注意
当在后台运行时 我们特别在意用户体验 因此当我们设计API来支持 这些用例时 我们有许多重要因素要考虑 我想强调其中三个因素 (关于后台执行的重要因素) 电源、性能和隐私
先讲电源 无论何时当你的app在前台或后台 运行时 都需要使用电源 随时间流逝 这会消耗能量 并会消耗电池
为了可视化这种消耗 让我们看一个时间线 左侧可能是一天的开始 当太阳升起时 而右侧可能是一天的结束 也许在一天结束时用户决定 给设备充电
我们用那个绿色充电区来代表它 我们用这些浅阴影矩形 来标绘app在前台运行的时间 我们用这些深阴影矩形 来标绘app在后台运行的时间 如果运行时间越长 我们就会越消耗电量 如果我们运行时间越短 电量消耗就会越少
因此 当我们设计API时 我们主要关注为了支持特定用例 所需要的运行时间 同时保持良好的电量 当使用这些API时 考虑如何有效地使用它们 当你完成后 请通过调用完成处理器来警告系统 那样 如果系统为你的app提供了 运行时间 你可以告诉系统说 “嘿 我提前完成了” 系统可以挂起你的app 然后你就会停止消耗用户的电量
接下来是性能 我们希望系统能尽可能流畅地运行 这意味着我们希望能快速启动app 并希望UI能快速响应 当我们在后台运行时 这尤其重要 原因是虽然我们可能会认为 一天之中只有一个app在运行
但实际上一天中不同的时间点 有多个app在运行 在前台和后台
当我们遮掩这件事时 我们可以看到我们的app可能正在 后台运行 而同时另一个app正在前台运行 或者当一个app正在前台运行时 有多个app正在后台运行 因此当我们设计API时 我们要考虑设置智能 CPU和内存限制 从而最小化对其它用途的影响 当使用这些API时 你应该注意这些限制是多少 从而不会影响用户正在积极去做的事 但更重要的是那样系统 不会终止你的app 然后当你的app以后再启动时 它的启动速度可能会变慢
最后一个重要因素是隐私 用户非常敏感 非常关心他们的私人数据 他们也许了解 app每一次在前台的运行 并期待能访问某些信息 他们可能没有意识到app每一次 在后台的运行
因此当我们设计API时 这意味着我们要使用不同的API 来适应不同的用例 每个API都要访问 自己特定的数据集 它需要支持那些数据 当使用这些API时 考虑一下对用户的透明度该有多大 并让他们了解你正在使用哪些数据
这些是关于后台执行 要考虑的三个重要因素 电源、性能和隐私 当我们返回到用例列表时 这些不同的用例 要转化为不同的API 每个API都要有不同的要求 才能实现所预期的行为 同时保持优秀的用户体验
现在我们已经有了个大概的了解 让我们深入一些最佳实践 遵循某些特定模式 了解一下API发生了哪些变更
为此 让我们以一款消息app为例 它可能有核心功能 比如 发消息或接打电话 然后它可能还有一些额外功能 比如 可以让用户设置消息免打扰 或下载以前的附件 现在我们要看一下这四个步骤 讲一下我们要使用哪个API来实现 每个功能
第一个功能是发消息 发消息是app的核心功能 如果我给我朋友发消息 我希望它能马上送达 而不是需要一天或一周
因此用户期待这个功能可以立即完成 虽然这通常很快 但有时候情况并非如此 也许网络拥挤或也许后台服务器慢 可能需要一些额外的时间 才能发送消息 在这段额外的时间内 用户可能甚至会离开app 或放下手机并锁定它 因此我们需要一种方式来保护 这个任务的完成 我们要确定我们的消息已成功发送 从而当用户返回app时不会发生 这种情况 “嘿 为什么我的消息没有发送给 我朋友”
这个功能要使用的API是 BackgroundTaskCompletion
它会为app 提供一些额外的运行时间 在app被挂起之前在后台运行 要使用这个API你要调用 UIApplicationBeginBackgroundTask 或调用 ProcessInfoPerformExpiringActivity 如果app是在扩展中运行的话 再说一次 这是为了要完成 从前台发起的任务 其它例子可能包括把文件保存到磁盘 或完成任意用户发起的请求 让我们在代码中看一下 我们那个发消息的例子
这是发送消息函数
在函数中 当我们创建发送操作之后 我们调用 BeginBackgroundTask 这就让系统了解 “嘿 我们正在执行任务 即使用户把app放到后台 也让我们继续完成它”
然后当我们发送完成后 我们…在完成代码块中 我们会告诉系统结束后台任务 我们不再需要时间了 这是为了以下情况 当系统为我们提供了一些时间 用户把app放到后台 而我们的任务执行完成后 我们要告诉系统把app挂起来 因此我们就不再消耗用户的电量了 或不再潜在地影响他们的性能了 我还要强调最后一件事 有些情况是也许系统给了你一些 额外的时间 但情况太糟糕了 也许网络特别拥挤 我们甚至在额外的时间内也不能 完成任务 为此 我们有一个过期处理器 系统可以在这个时候调用过期处理器 在这个例子中 我们会给用户发布一条用户通知 一则本地通知 内容是“嘿 请回到app中 因为消息未发送”
那么回顾一下 当我们发送消息时 我们用BackgroundTaskCompletions 保护它的发送
我们想确保我们根据用户的动作 开始了这个任务 我们不想等到我们进入后台 才能调用 BeginBackgroundTask 因为如果我们这样做了 会限制在系统挂起app之前 我们积极尝试发送消息的时间
现在我们讲了发消息 接下来让我们讲接打电话 (接打电话) 我可能一直想给我的朋友们发消息 但有时你只想接通电话 快速接听电话 告诉他们一些事 这样你就不需要打字了 有个API能实现这个功能 即VoIPPushNotifications 这是一种特殊的推送类型 可以启动你的app 并为它提供一些运行时间 那样你可以向用户呈现 有人给他们打电话的事实 然后用户可以接电话
为了实现这个功能 你只需要在注册VoIP推送时
在PK推送注册中 设置VoIP推送类型
今年有个新改进 你必须在didReceiveIncomingPush 回调中 使用CallKit报告来电 这一点非常重要 否则你的app将被终止 并且如果你反复这样做 或如果导入来电反复失败 系统可能会完全停止启动app 进行VoIP推送
让我们看一下如何在代码中 适应这个变更
这是我们的didReceiveIncomingPush 回调 在回调内我们看到如果推送类型 是VoIP 我们将使用来自推送有效载荷的信息 来填充CX呼叫更新对象 然后使用CX提供器报告新来电
你需要确保在那个方法返回之前 报告来电 否则系统…系统将终止app的运行 还有一些其它小技巧 如果你在推送有效载荷中包含 来电信息 然后你将拥有快速呈现 那个来电UI所需要的全部信息 因此请尝试包含尽可能多的信息 从而你可以呈现尽可能丰富的UI
第二 确保你把推送的 APN过期时间 设置为零或一些很小的值
这样用户将不会在来电几分钟后 收到一个推送 而此时已经停止拨打电话了 比如说 如果某人给我打电话了 而推送花了两分钟时间来发送 然后一旦推送在两分钟之后才送达 我不想报告来电 因为那个人很可能已经不再 拨打电话了 因此如果我们把过期时间设置为零 那意味着要立即提交或提交失败 或几秒之内完成 然后我们就知道 如果设备正在接收推送 这仍然是一个相关的来电
重点是要注意如果你想发送通知 你总是可以使用标准推送 而不是全屏… 那样你就不需要在呼叫UI中 全屏呈现通知 并且你可以使用通知服务扩展 如果你需要修改推送内容的话 比如 如果你需要解密推送内容的话
那么这就是VoIP推送和接打电话 现在让我们讲一下静音线程 (静音线程) 当用户有个消息app时 他们可能会给许多不同的朋友 或许多不同的朋友群发送消息 其中有些线程可能会很繁忙 用户可能不想收到 那个特定线程的警告 但内容仍然可能是相关内容 内容可能仍然不错 当用户返回到app中时 他们想查看消息 他们只是不想当每次接收消息时 都要震动设备并收到通知 因此我们需要一种方式可以警告设备 而不是用户 关于有可用的新内容了
为此你应该使用后台推送
后台推送是一种机制 告诉设备 有新数据可用 而不警告用户
要使用这些 你只需要把内容可用标志设置为一 并进行推送 不需要警告 不需要声音 或不需要任何标记 然后系统将决定 何时启动app下载内容 根据电量和性能影响 并尝试将影响最小化 我们可以在时间线上看一下这个过程 看起来类似这样
用户可能正在使用app 并决定静音某个线程 然后在将来的某个时间点 某人可能在那个线程上发了消息 设备将收到后台推送
在此之后的某个时间app将被启动 并获得一些运行时间来取回那个内容
然后当用户稍后返回到app中时 打开app 用户可以打开线程 并看到已经收到内容了 对于后台推送也有一些非常重要的 新改进 (后台推送) 你必须把APN优先级设置为五 否则app将不能启动
并且你还应该把APNS推送类型 设置为后台 这是watchOS所必需的 但我们强烈建议在所有平台上 都这样做 如果你想获得关于在 watchOS上的推送的更多信息 昨天有场单独的Watch app 演讲 你可以参考一下
回顾一下 对于静音线程 使用后台推送 作为下载内容的最佳方式 如果app没有获得运行时间 在收到后台推送后 你总是可以在app重新进入前台时 下载那些内容
现在让我们谈谈下载以前的附件
假如用户登录了他们的账户 他们在一台新设备上登录了 他们可能想立即从账户中 获取某些内容 比如对话列表或某些最近的消息
但可能有一批比较老的内容 如果你不在用户进入app时 就立即下载它 那非常好
想象一下 如果我们可以在设备充电时和闲置时 下载的话 我们为什么要在用户处于前台时 下载呢 那可能会潜在地 影响他们的性能或电量
实现方式是使用 任意后台URL会话 这可以让系统推迟下载 直到出现一个更好的下载时间 这个API可以让你传递更多信息 从而它可以更智能地安排时间 要使用它 你需要像往常那样 设置后台URL会话 然后把任意标志设为真
让我们看一下你可以传入的一些 额外信息 从而使系统变得更智能
你可以传入超时间隔 也许你不希望系统一直尝试下载 因此你希望可以界定系统可以下载 多长时间
你可以传入一个最早开始时间 也许你不想执行上传或下载 直到将来的某个时间点 并且你可以传入所预期的工作量大小 从而系统了解当运行下载时 有多少工作要做
当你正在下载以前的附件时 如果可能的话 你希望推迟这个操作 从而最小化对用户可见的影响 我们可以对任意可推迟的下载或上传 实施同样的原则 也许你有一些分析 你想在一个更合适的时间批量上传 或也许有一些用户拍摄的照片 你想稍后再进行备份
回顾一下 我们有一款消息app 它有一些核心功能 你可以发消息、接打电话 允许用户设置消息免打扰 并且你还可以下载以前的附件 我们使用了不同的API 实现每个功能 我们使用 BackgroundTaskCompletion 保障即使用户离开app 消息也能发送出去 我们使用VoIP推送 作为启用接打电话的方式 我们使用后台推送 作为给app提供运行时间 以响应新内容的最佳方式 并且我们使用任意URL会话 在合适的时间下载附件
但还有许多其它用例 我们现有的模式目前还没有覆盖到 因此我想邀请我同事 Thomas上台来 介绍一种新的后台模式和框架 是特别针对这些用例设计的 谢谢大家
谢谢Roberto 让我们讲一下这些用例 (新的后台任务框架) 这些是比如主动与服务器同步状态 清理数据库 或把数据备份到Cloud 这些是可推迟的维护型任务 你最好在后台执行 从而不影响前台用户活动 如今我们看到的是 app在进入后台后就立即执行 这种任务 在一整天之中 这些任务其实可以累计起来一起执行
如果你可以把全部那种任务都推迟到 稍后执行怎么样 也许是当设备充电时或闲置时?
这就是我们今年引入的新功能 一个全新的后台模式和与之匹配的 一个框架 我们叫做后台任务 后台任务 可以让你稍后在后台执行任务
它在iOS、iPadOS、 tvOS上可用 对Mac上的 iPad app也可用
我们不仅引入了这个新后台模式 我们调用后台处理任务 我们还利用这个机会 改善了现有API 在后台刷新app的功能
先讲一下新后台模式 后台处理任务 可以在系统友好时间为你的app 提供几分钟的运行时间 从而你可以执行我之前提到的 可推迟的维护级任务以及新任务 比如设备上、 Core ML、在后台训练和推断 你可以从它们各自的演讲中 了解更多内容 (后台处理任务) CPU监控是系统的一个功能 自动终止在后台使用了太多 CPU循环的app 以保护用户的电量 有史以来我们首次 可以让你在任务处理过程中 关闭CPU监控 从而你可以在设备充电时 充分利用硬件
最后我们会确保你有资格 运行这些任务 只要你在app处于前台时 请求执行这些任务 或如果你的app最近在前台使用过 也可以
(后台APP刷新任务) 接下来我要讲用于后台app刷新的 新API
这是个新API 但它的政策与当前API一模一样 这意味着app每次启动时将获得 30秒的运行时间 用于获取新内容并在一天内保持 一直有最新内容
app的启动频率以及何时启动 取决于用户在过于使用app的方式
因此如果用户一般在早上、 下午和晚上使用你的app 系统将会了解这种模式 并在这些时间之前不久 启动你的app 因此你就有机会获得你所需要的内容
这也意味着 如果app的使用频率不高 启动频率可能也不高
正如我所提到过的 这是用于后台app刷新的新API 因此我们不推荐使用你在这里看到的 UI Application中的现有API
但这些API可以继续使用 它们在iOS、iPadOS 和tvOS设备上的使用方式不变 但Mac上不支持它们 因此一定要采用后台任务 在Mac上执行后台app刷新
让我们看看这个API是如何运作的
假如我们有一款app 它包含一些扩展
你将与之交互的原始对象是 后台任务调度程序
后台任务调度程序 是系统智能的、 动态的活动调度程序的界面 它持续监控各种系统情况 包括电量等级、app的使用、 网络的连通性等等
当app正在运行时 你可以请求它稍后在后台唤醒它 并执行任务 为此 你要创建一个后台任务 请求对象的实例
响应你要实施的任务的类型 在这个例子中 我们想执行后台app刷新 因此我发起了一个 后台app刷新任务请求
我们把它提交给调度程序
如果你想执行多种类型的任务 你可以提交多个请求 在这个例子中 我们还想执行一些数据库清理 因此我也要发起一个 后台处理任务请求并提交它
你还可以当扩展正在运行时 从扩展中提交请求
因此如果你的键盘扩展 想根据用户的键入习惯进行学习 它也可以创建一个后台处理任务请求 并提交它 你可以看到 你有多个等待处理的 后台处理任务请求 每个都代表你希望app执行的 特定任务
现在调度程序知道我们的app 要做的全部任务
当满足所有必要的系统条件 和政策时 它将执行那个任务 唤醒你的app并在后台启动它 给它提交一个 响应你应该实施的那个任务的 后台任务对象 在这个例子中 我们有后台app刷新任务 因此我们现在可以实施 后台app刷新获取内容 并更新我们的UI
当我们完成后 我们要调用 SetTaskCompleted 它会把任务标记为完成并挂起app
根据你对后台任务请求的配置方式 以及各种系统情况和政策 我们可能选择同时启动app执行 多个任务 在这个例子中 系统启动了我们的app 系统向app同时提交了之前请求的 两个后台处理任务
当app启动时 系统就为它提供一段有限的时间 来完成分配给它的任务 那个时间是按启动来分配的 而不是按任务分配 因此你应该准备好 在分配给你的时间内 同时地处理分配给你的全部任务 同时请注意键盘扩展发起的 处理任务请求 会提交到主app中 那是因为始终是启动主app 来处理后台任务 而不是启动扩展
当app完成执行必要的任务之后 在系统分配给它的全部后台任务 对象上调用SetTaskCompleted 然后就会挂起app 这就是关于如何使用 后台任务API的高级概述 你创建后台任务请求 并提交给后台任务调度程序 等待系统在后台启动你的app 执行必要的任务 然后在BG任务对象上调用 SetTaskCompleted
为了让你了解如何在你的app中 实施这个API 我要给你做一个演示
这是我们的app 它叫做Color Feed 是款典型的社交媒体类型的app 除了照片信息 你还可以获得最近流行颜色的信息 你可以看到 我可以滚动并查看 不同的时间点的最新颜色
我其实想做的是 确保我的app在一天的时间里 可以保持拥有最新消息 并进行自我刷新 而不需要用户进入app并手动操作 处理这个问题最完美的工具是 后台app刷新 我要通过后台任务实施这个操作
你要做的第一件事就是 向info.plist中 添加所需要的键 声明你对后台任务 和后台app刷新的支持 因此我要进入我的项目设置
点击我app的目标
并进入“签名和功能”选项卡
我要点击加号并为后台模式 添加新功能
你可以看到 它增加了这个新的部分 我们需要给这种类型的任务 选择合适的后台模式 在这个例子中 对于后台app刷新 该框标记为后台提取 就与在老API中一样 因此我要继续并查看一下
接下来我要进入我的 请求info.plist文件 就在这里…
我要点击加号并添加一个新键
这个键叫做PermittedBackground TaskSchedulerIdentifiers 它是一个字符串的数组 这个数组中的每个字符串 都唯一标识你的app要执行的 某个特定的任务 并且它在你的app内应该是唯一的 我们推荐使用反向DNS表示法 避免与你可能使用的任何第三方框架 发生冲突
在这里我要扩展那个数组 并点击加号来添加新字符串
我要把它命名为 com.colorfeed.refresh
并点击保存 接下来当我的app启动时 我需要实际实施要处理的代码 我要在app委托中实现
我要进入app委托文件 我要做的第一件事是导入后台任务
好吧 下一步 就是告诉系统当你启动时你想做什么 你可以通过在app完成启动之前 就注册启动处理器来实现 didFinishLaunching 和Options方法 我要调用…
共享后台任务调度程序 用标识符注册任务 传入我刚放在info.plist 中的同一个标识符
下一个参数是一个分派队列 我的处理器将调用分派队列 并且如果我想在app中 同步执行其它任务 我可以指定我要使用的队列 或我可以传入无 系统将替我创建一个后台串行队列
下一个参数是 启动处理器 当在后台启动app执行后台任务时 调用它 你可以看到 它接受后台任务的一个参数
我要做的是 调用一个方法…我要编写一个名为 HandleAppRefresh的方法 把那个后台任务对象向下转换为 后台app刷新任务 因为这是用于后台app刷新的参数
现在我要继续并编写那个 HandleAppRefresh方法
我在这里编写了 用于实施后台app刷新 所需要的全部代码 它将从服务器获取最新内容 更新数据库并更新UI 为了把这个与后台任务集成到一起 我需要做两件事 第一件是处理过期 系统为你的任务分配了有限的 完成时间 当你的时间差不多要用完时 我们会警告你并给你提供一个机会 让你快速完成全部工作 系统可能还选择提早终止你的任务 如果系统决定当前情况 不足以运行你的任务的话
我要做的就是在任务上设置一个 过期处理器…
在过期处理器中 我要在我的操作队列上调用 CancelAllOperations 这会停止我正在做的全部工作 并取消我甚至还没开始的任何工作
我要做的下一件事是 完成之后在任务上调用 SetTaskCompleted
即使在系统调用过期处理器之后 我也需要调用SetTaskCompleted
如果我不这样做 系统实际上可能会终止我的app 那会影响稍后的启动性能 你绝对不想那样做 我要做的是 我要…
在那个队列中的最后一个操作 完成之后 调用 SetTaskCompleted 我要充分利用这一点 即操作总是会调用它们的完成代码块 无论操作是被提早取消或是正常完成 并且我通过这一点来决定 我的任务是否成功完成
好吧 最后一步… 是安排后台任务请求 并且我要当app进入后台时再安排 因为那时用户会停止使用app 因此我要继续并编写这个功能
你可以看到 我正在调用我刚才编写的那个 ScheduleAppRefresh方法 而我的app确实进入了后台方法 在这里我要创建一个后台app 刷新任务请求对象 并给它传入那个相同的标识符
然后我把那个请求提交到 任务调度程序
有一个额外属性 我想在任务请求对象上调用 即最早开始时间 你可以通过这个给任务指定开始推迟 在这个例子中 我指的是不要开始app刷新 不要开始刷新app 除非在我安排 它刷新后的至少15分钟之后再执行 这让我获得了与老的 SetMinimumBackgroundFetchInterval API一样的行为
我安排我的任务 但实际上我很可能还想做另一件事
因为每个单个后台任务请求对象 恰好响应一次启动 现在如果系统启动了我的app 执行后台app刷新 系统将不会再次启动它 直到用户打开并离开我的app 但我并不希望这样 我希望能一直刷新 因此我要做的就是 在我的handle方法中 调用 ScheduleAppRefresh 我会在系统启动app执行 现有任务时 立即发起另一个请求
就是这个 这就是我要处理app中的 后台app刷新 所需要编写的全部代码
但因为我正在使用app 并且正在滚动浏览
我看到那有许多很久之前的内容 那可能是不再与用户相关的内容 只是占用磁盘空间 如果我们可以为用户清理数据库 那真是太棒了 最好的工具就是后台处理任务 我要继续并实施它
跟以前一样 我要进入我的项目设置
进入“签名和功能”选项卡 这一次 在后台模式中 我要确保勾选后台处理复选框
我要进入 我的info.plist…
并点击加号添加新标识符 我把它命名为 com.colorfeed.dbcleaning…
并点击保存
然后跟以前一样 我要进入app委托… 并再次调用注册
这跟我之前的调用相同 除非我传入了新标识符 并且我要调用 HandleDatabaseCleaning 并向下转换为后台处理任务
现在我要继续并实施 HandleDatabaseCleaning
我已经把这段代码与后台任务集成了 它的功能是删除昨天之前的一切数据 你可以看到 我设置了过期处理器 和取消我的全部操作 并且当我完成后成功调用了 SetTaskCompleted 有一点不同 就是我一直追踪我上次成功清理 数据库的时间
这是因为当我安排任务时 我想谨慎地使用系统的资源 我不想当用户每次离开app时 都安排数据库清理任务 如果我的数据库 实际上不需要清理的话 我要做的就是编写一个 ScheduleDatabaseCleaning方法 如果需要的话
我会检查 是否距离上次清理已经过去了 至少一周的时间 如果不是 我就不采取任何措施 我会立即跳出 反之我将继续并安排那个请求 我要创建一个后台处理任务请求 并给它传递我之前传递过的同一个 标识符
在后台处理任务请求上有一些 额外的属性 你可能要引起注意 第一个是要求网络连接 实际上它默认设为假 你应该确保把它设为真 如果执行你的任务真的需要 网络连接的话 否则我们可能会在没有网络连接时 启动你的任务 那样你就不能完成很多工作 在我们的例子中 我们要做一些本地数据库维护 因此我们可以把它保留为假
下一个是要求外部电源
根据设备的特定类型 和各种系统情况和政策 我们可能倾向于当设备充电时 启动app 然而如果你请求 如果你请求你自己执行密集的任务 并使用大量资源 我们强烈建议你把这个设为真 那样有助于保存用户的电量 把这个设为真 也是你对CPU密集型任务 禁用CPU监控的方式
就是这么多了 我要继续 并把那个请求提交到调度程序 如果需要的话 我会在app进入后台时再执行
这是我要处理后台app刷新 和后台处理任务所需要编写的 全部代码 但我如何知道这些代码没问题呢?
我想我是个完美的程序员 但是 显然情况并非总是如此 端对端测试的最好方式是 把它放在设备上 并像用户一样使用它 那会确保你可以获得 用于执行特定任务所需要的 时间和政策
但我们还知道当你编码时 你没有时间坐在那儿等着 因此我们添加了一些方法 你可以在调试器中调用 用于调试后台任务的使用 现在让我来演示一下
我要创建并在我的iPhone上 运行这个新版后台任务
你可以看到 它启动了 现在我要把它放到后台去
从而确保安排我的任务请求
我再把它放到前台来 在这里 我要点击底部的暂停按钮
这将会进入调试器
我可以看到控制台
我要做的就是 粘贴命令 你可以从文档中找到命令 因此不需要把它记下来
在这里我要做的就是 用我想要模拟的任务的标识符 替换这个 “task identifier” 我想测试后台app刷新 因此我要键入 com.colorfeed.refresh
但步骤与我的处理任务一样 我要按回车… 你可以看到 系统已经识别我想模拟一次启动 执行后台app刷新任务
我要点击这里的播放按钮
你可以看到 系统开始执行我的app刷新任务 我的app主动地进行了刷新 我可以看到代码起作用了
我要再次点击暂停 这一次我要确保过期也没问题 因为它也同等重要
我要做的就是输入同一个命令 但这一次我要用过期替换“启动” 并按回车
你可以看到 系统识别到我发起了这个请求 当我点击播放时 你应该可以看到我的app会成功地 停止刷新 识别到那个任务已过期 并把任务标记为完成 现在我知道对于后台任务 我的app已经成功地实施并测试了 后台app刷新和后台处理任务
谢谢 当你使用我们的框架时 还有一些额外的注意事项 你可能要引起注意
第一 请注意对最早开始时间的设置 不要把时间设置得太远 如果你把它设置得太远 并且在此期间用户也没有返回到 你的app中 我们可能会选择完全不启动你的任务 那只是为了保护用户的预期和隐私 几个月都不使用你app的用户 不会期待它突然开始在后台运行 因此我们建议你把最早开始时间 把你推迟的最早开始时间设置为 一周或更短
接下来请确保在处理任务过程中 你需要访问的任何文件 当设备被锁定时可访问 因为我们一般会在那时启动你的任务
我们保证我们不会开始你的任务 直到用户第一次锁定他们的设备 因此请确保你要访问的任何文件 大部分文件保护类型都是完整的 直到第一次用户验证
我们在传统的单个窗口的 UIKit app中 演示了如何实施后台app刷新 但你知道的 今年我们通过 UIScene API 引入了多窗口app 如果你采用那个API 可以在合适的时间调用UIApplication RequestSceneSessionRefresh 从而告诉系统 App切换器中的快照需要更新 你可以在它们各自的文档中找到 相关详情
最后 BGTaskScheduler.submit 是一个阻塞的同步调用 我们之所以那样设计它是因为 那样会简化对它的采用方式 当你进行调度时 当你进入后台时 这是常见的情况 然而如果你计划 在更具性能敏感性的情境中进行调度 比如当app启动时 你要确保在后台队列上调用它 从而不会阻塞主线程并妨碍启动性能
好吧 总结一下我们今天讲过的内容
但请认真考虑 如何在后台使用运行时间 请谨记我们在设计我们的API时 所考虑的要素 比如电源、性能和隐私
请一定使用合适的后台模式 来完成你要执行的任务 并获得你想要的用户体验
最后请使用新后台任务API 来安排稍后在后台中要执行的任务 请使用后台app刷新任务 保持app拥有最新内容 并使用后台处理任务来执行 可推迟的维护级任务 当设备闲置时和充电时
网友评论