升级 iOS 13.2 后应用在后台频繁被杀给大量用户带来困扰。网络上wakeup 分析日志流传甚广,也有人判定由于应用不遵照 iOS 后台唤醒规则,因此被杀。swift
肯定的是 wakeup 调用不是 App 被杀掉的直接缘由,不能简单归因后台频繁被杀是开发者的问题。如今 Apple 提供了 MetricKit API 能够从系统层面获取应用后台被杀的缘由,并给出了一些改善建议。xcode
系统给出的应用程序后台终止的主要缘由 :缓存
新的MetricKit API 提供后台被杀的缘由安全
MXBackgroundExitData
经过提供每次应用程序被终止时的退出计数,了解为何应用程序会被杀死。网络
崩溃是最直接的终止类型。可能发生的缘由有如下3种app
这些事件将在crashlog上生成,并自动向咱们报告。除了Xcode organizer以外,MetricKit还为每一个设备增长了更多的API,即 "MXCrashDiagnostic"。ide
MXCrashDiagnostic
将提供如下信息post
另外一类被杀是因为Watchdog事件而发生的,该事件发生在一些关键的过程当中的超时。ui
CPU资源限制是指后台CPU持续负载较高。 在Xcode 12中增长了一些解决方案。spa
MXCPUExceptionDiagnostic
实现电量异常报告。BGProcessingTask
。应用程序占用太多内存。一些解决方案 :
注意:这不是你的应用程序的错误,它是最多见的退出缘由。发生这种状况是由于系统为活动的应用程序腾出内存。
如何下降内存压力退出率?
建议在后台作如下操做。
还有关于如何从内存压力退出中恢复的建议。
当进入后台时,咱们可使用 "beginBackgroundTask "和 "endBackgroundTask "来执行后台任务(系统会给你30秒的时间来完成任务)
UIApplication.beginBackgroundTask(expertationHandler:)
UIApplication.endBackgroundTask(_:)
复制代码
给BackgroundTask命名来排查没有结束后台任务的问题。
UIApplication.beginBackgroundTask(withName:experienceHandler:)
复制代码
为何?
另外一个解决办法是使用expirationHandler
。
expirationHandler
做为保障措施,不要彻底依赖它。endBackgroundTask
。let handle = MXMetricManager.makeLogHandle(category: "DatabaseExpHandler")
mxSignpost(.event, log: handle, name: "Entered")
cancelOperations()
closeDatabase()
mxSignpost(.event, log: handle, name: "Exited")
UIApplication.shared.endBackgroundTask(backgroundTaskIdentifier)
复制代码
让咱们检查 "MXMetricPayload",看看标记数量,并检查标记数量是否有不平衡(非成对出现)。
另外一种改善应用程序终止调试的解决方案是在作一些后台工做以前检查backgroundTimeRemaining
。
示例代码 :
let minimumTimeRemaining = min(5, estimateProcessingTime(inputData))
if UIApplication.shared.backgroundTimeRemaining > minimumTimeRemaining {
// 剩余时间足够,调用开始后台任务
return UIApplication.shared.beginBackgroundTask { ... }
}else {
// 时间不够,将这项工做推迟到之后进行。
registerProcessingTask(inputData)
return .invalid
}
复制代码
下一步须要避免内存泄漏UIBackgroundTaskIdentifier
。使用局部变量而不是实例变量来保存UIBackgroundTaskIdentifier
,这样能够防止内存泄漏,由于它将在不一样的内存上分配。
示例代码 :
@IBAction func beginDataExport(sender: UIButton) {
var taskId.UIBbackgroundTaskIdentifier = .invalid: UIBbackgroundTaskIdentifier = .invalid
taskId = UIApplication.shared.beginBackgroundTask {...}。
//归档后结束后台任务,这须要几秒钟的时间。
ArchiveUtility.exportUserData(completion: ()->()) {
UIApplication.shared.endBackgroundTask(taskId)
}
}
复制代码
wwdc2020/10078 为何个人应用程序被杀死? developer.apple.com/videos/play…
wwdc2020/10081 MetricKit的新功能: developer.apple.com/videos/play…
MetricKit API 后台应用程序退出计数文档: developer.apple.com/documentati…
MetricKit 及它的使用方式,也提供了一个收集 MetricKit 数据的自建 Web 服务方案: nshipster.com/metrickit/
UI状态恢复文档: developer.apple.com/documentati…