Apple Screen Time API使用求助:监控回调突然中断问题
Apple Screen Time API 示例代码与回调停止问题排查
一、基础Screen Time API(结合Family Controls)示例代码
1. 获取家长控制授权
import FamilyControls let authorizationCenter = AuthorizationCenter.shared authorizationCenter.requestAuthorization { status in guard status == .authorized else { // 处理未授权逻辑,比如提示用户开启权限 return } // 授权成功后初始化监控 setupDeviceActivityMonitoring() }
2. 初始化设备活动监控
import DeviceActivity func setupDeviceActivityMonitoring() { let deviceActivityCenter = DeviceActivityCenter.shared // 定义监控事件:比如每30分钟触发一次阈值提醒 let usageEvent = DeviceActivityEvent(threshold: .init(minute: 30)) let events: [DeviceActivityEvent.Name: DeviceActivityEvent] = [ .init(rawValue: "30MinuteUsageAlert"): usageEvent ] // 设置监控时间段:比如从当前时间开始,持续1小时,每日重复 let calendar = Calendar.current let intervalStart = calendar.dateComponents([.hour, .minute], from: Date())! let intervalEnd = calendar.dateComponents([.hour, .minute], from: Date(timeIntervalSinceNow: 3600))! let schedule = DeviceActivitySchedule( intervalStart: intervalStart, intervalEnd: intervalEnd, repeats: true, calendar: calendar, timezone: .current ) let activityName = DeviceActivityName(rawValue: "DailyUsageMonitor") do { try deviceActivityCenter.startMonitoring(activityName, during: schedule, events: events) } catch { NSLog("启动监控失败:\(error.localizedDescription)") } }
3. DeviceActivityMonitor扩展实现
import DeviceActivity import FamilyControls class DeviceActivityMonitor: DeviceActivityMonitorExtension { override func intervalDidStart(for activity: DeviceActivityName) { NSLog("监控时间段启动:\(activity.rawValue)") } override func intervalDidEnd(for activity: DeviceActivityName) { NSLog("监控时间段结束:\(activity.rawValue)") } override func eventDidReachThreshold(_ event: DeviceActivityEvent.Name, activity: DeviceActivityName) { NSLog("阈值触发:\(event.rawValue),对应活动:\(activity.rawValue)") // 示例:触发阈值后屏蔽指定App let controlsCenter = FamilyControlsCenter.shared let targetApps = ApplicationToken.currentApplications.filter { $0.bundleID == "com.example.targetApp" } controlsCenter.setAuthorizationStatus(.denied, for: targetApps) } }
二、你的代码问题分析与回调停止解决方案
1. 核心问题:创建过多事件
你循环创建了60个每分钟触发的事件,这会触发系统资源限制——Screen Time对同时监控的事件数量有隐性上限,过多事件会导致系统丢弃回调甚至终止监控。
优化方案:
- 只监控关键时间阈值(如10、30、60分钟),而非每分钟都创建事件;
- 如果需要连续监控,可在事件触发后动态注册下一个时间段的监控,而非一次性批量注册。
优化后的代码示例:
var scheduleDuration = 60 // 只保留关键监控节点 let keyThresholds = [10, 30, 60] var usageEvents: [DeviceActivityEvent.Name: DeviceActivityEvent] = [:] for threshold in keyThresholds { guard threshold <= scheduleDuration else { continue } let event = DeviceActivityEvent(threshold: .init(minute: threshold)) usageEvents[.init(rawValue: "scheduleID_\(threshold)")] = event } // 后续启动监控逻辑不变 let schedule = DeviceActivitySchedule(intervalStart: intervalStart, intervalEnd: intervalEnd, repeats: false) let activityName = DeviceActivityName(rawValue: "\(scheduleID)") do { try deviceActivityCenter.startMonitoring(activityName, during: schedule, events: usageEvents) } catch { NSLog("Error monitoring device schedule - \(error.localizedDescription)") }
2. 回调突然停止的其他排查点
- 扩展生命周期:DeviceActivityMonitor是后台扩展,系统可能因资源紧张终止它。确保扩展
Info.plist配置正确:NSExtension->NSExtensionPointIdentifier必须设为com.apple.deviceactivity-monitor;- 扩展内逻辑要轻量化,避免耗时操作。
- Schedule有效性:检查
intervalStart和intervalEnd的时间逻辑,若起始时间晚于结束时间、或时间已过期,监控会自动停止。建议每次启动前验证时间范围。 - 权限状态:系统偶尔会丢失授权,可在主App定期检查
AuthorizationCenter.shared.authorizationStatus,若变为未授权则重新请求。 - 命名冲突:确保
DeviceActivityEvent.Name和DeviceActivityName的rawValue唯一,重复命名会覆盖旧监控导致回调异常。 - 系统节流:iOS对Screen Time监控频率有控制,过于频繁的事件触发会被系统节流,建议合理设置阈值间隔。
内容的提问来源于stack exchange,提问作者Akilan C B
相关产品推荐
相关产品推荐

