升級 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…