如何检测Screen Time进程崩溃?Swift TabView切换异常技术问询
检测Screen Time进程崩溃的可行方案
针对SwiftUI TabView中快速切换标签页导致Screen Time进程崩溃、报告空白的问题,以下是几种无需每次切换强制刷新的崩溃检测方案:
1. 包装DeviceActivityReport监听视图生命周期
通过UIViewRepresentable包装原生DeviceActivityReport,监听其底层视图的window绑定状态——进程崩溃会导致视图突然脱离window,以此作为崩溃信号:
struct DeviceActivityReportWrapper: UIViewRepresentable { let context: DeviceActivityReport.Context let filter: DeviceActivityFilter? var onCrashDetected: () -> Void func makeUIView(context: Context) -> some UIView { let reportView = DeviceActivityReportUIView(context: self.context, filter: self.filter) // 监听视图的window绑定变化 reportView.observe(\.window, options: [.new, .old]) { _, change in if change.oldValue != nil && change.newValue == nil { DispatchQueue.main.async { self.onCrashDetected() } } } return reportView } func updateUIView(_ uiView: UIViewType, context: Context) {} }
在标签页视图中使用该包装器,仅在检测到崩溃时触发刷新:
struct Tab2View: View { @State private var needsRefresh = false var body: some View { Group { if needsRefresh { DeviceActivityReport(Utils.weeklyContext, filter: Utils.filterWeekly) .id(UUID()) } else { DeviceActivityReportWrapper(context: Utils.weeklyContext, filter: Utils.filterWeekly) { needsRefresh = true } } } .onAppear { if needsRefresh { needsRefresh = false } } } }
2. 监听Screen Time授权状态突变
进程崩溃可能导致授权状态异常回落,通过监听DeviceActivityAuthorizationCenter的状态变化来检测崩溃:
struct TabContainerView: View { @State private var lastAuthStatus: DeviceActivityAuthorizationStatus = .authorized private let authCenter = DeviceActivityAuthorizationCenter.shared var body: some View { TabView { Tab1View() .tabItem { Label("Tab 1", systemImage: "1.circle.fill") } Tab2View() .tabItem { Label("Tab 2", systemImage: "2.circle.fill") } } .onReceive(authCenter.$authorizationStatus) { newStatus in if lastAuthStatus == .authorized && newStatus != .authorized { // 授权状态异常回落,判定为进程崩溃,触发全局刷新 NotificationCenter.default.post(name: .refreshScreenTimeReports, object: nil) } lastAuthStatus = newStatus } } } // 扩展通知名 extension Notification.Name { static let refreshScreenTimeReports = Notification.Name("RefreshScreenTimeReports") }
在各标签页视图中监听通知,仅在需要时刷新:
struct Tab2View: View { @State private var refreshId = UUID() var body: some View { DeviceActivityReport(Utils.weeklyContext, filter: Utils.filterWeekly) .id(refreshId) .onReceive(NotificationCenter.default.publisher(for: .refreshScreenTimeReports)) { _ in refreshId = UUID() } } }
3. 基于视图渲染状态的可用性检查
在标签页切换后,通过定时器检查DeviceActivityReport的渲染尺寸——进程崩溃会导致视图无法正常渲染,尺寸为0:
struct Tab2View: View { @State private var isReportValid = true var body: some View { DeviceActivityReport(Utils.weeklyContext, filter: Utils.filterWeekly) .background(GeometryReader { geo in Color.clear.onAppear { DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { // 尺寸异常判定为崩溃 if geo.size.width == 0 || geo.size.height == 0 { isReportValid = false } } } }) .id(isReportValid ? UUID() : UUID()) .onAppear { if !isReportValid { isReportValid = true } } } }
以上方案均仅在检测到崩溃时触发报告刷新,避免了每次切换标签页都重新加载完整报告的开销,与Jomo、Opal等应用的优化思路一致。
内容的提问来源于stack exchange,提问作者NeuraCache
相关产品推荐
相关产品推荐

