About the problem that DeviceActivityMonitorExtension does not work

I am developing an app that can help users disable selected apps at a specified time, so that users can get away from their phones and enjoy real life. Here is my data structure:

extension ActivityModel {
    @NSManaged public var id: UUID                    
    @NSManaged public var name: String        
    @NSManaged public var weeks: Data     
    @NSManaged public var weekDates: Data           
    @NSManaged public var appTokens: Data         
}

Among them, weeks is of [Bool] type, indicating which weeks from Sunday to Saturday are effective; weekDates is of [[Date,Date]] type, indicating the effective time period; appTokens is of Set<ApplicationTokens> type, indicating the selected apps。

At the beginning, I will open a main monitor:

let deviceActivityCenter = DeviceActivityCenter()
do{
        try deviceActivityCenter.startMonitoring(
            DeviceActivityName(activityModel.id),
            during: DeviceActivitySchedule(
              intervalStart: DateComponents(hour: 0,minute: 0,second: 0),
              intervalEnd: DateComponents(hour: 23,minute: 59,second: 59),
              repeats: true
        )
    )
}catch {
    return false
}

Since the time range may be different every day, I will start the sub-monitoring of the day every time the main monitoring starts:

override func intervalDidStart(for activity: DeviceActivityName) {
    super.intervalDidStart(for: activity)
    if activity.rawValue.hasPrefix("Sub-") {
            ActivityModelManager.disableApps(
                Tools.getUUIDFromString(activity.rawValue)
            )
            return
     }    
    let weekIndex = Calendar.current.component(.weekday, from: .now)
    let weeks = ActivityModelManager.getWeeks(activity.rawValue)
    if weeks[weekIndex] {
        let weekDates = 
              ActivityModelManager.getWeekDates(activity.rawValue)
        let deviceActivityCenter = DeviceActivityCenter()
        do{
              try deviceActivityCenter.startMonitoring(
                  DeviceActivityName("Sub-" + activityModel.id),
                  during: DeviceActivitySchedule(
                    intervalStart: getHourAndMinute(weekDates[weekIndex][0]),
                    intervalEnd: getHourAndMinute(weekDates[weekIndex][1]),
                    repeats: false
                )
            )
        }catch {
            return
        }
    }esle {
        return
    }
}

I will judge whether it is main monitoring or sub monitoring based on the different activity names. When the sub-monitor starts, I will get the bound application and then disable it:

static func disableApps(_ id : UUID){
        let appTokens = ActivityModelManager.getLimitAppById(id)
        let name = ManagedSettingsStore.Name(id.uuidString)
        let store = ManagedSettingsStore(named: name)
        store.shield.applications = appTokens
        return
}

When the child monitoring is finished, I resume the application:

static func enableApps(_ id : UUID){
        let name = ManagedSettingsStore.Name(id.uuidString)
        let store = ManagedSettingsStore(named: name)        
        store.shield.applications = []
}

The above is my code logic. When using DeviceActivityMonitorExtension, I found the following problems:

  1. intervalDidStart may be called multiple times, resulting in several sub-monitors being started.
  2. After a period of time, the monitoring is turned off.
  3. The static methods enableApps and disableApps are sometimes not called

On February 9, I encountered the situation where the monitoring process was killed again. The monitoring processes of my two different applications were all killed, and I don’t know why. The only difference is that on February 8, I updated the system. However, on February 8, the monitoring still existed. In order to reduce memory, I used static methods in monitoring. And they were all looped at 0:00.

After it expired on February 9, it also expired on February 14. The failure codes are as follows:

let deviceActivityCenter = DeviceActivityCenter()
let deviceActivityName = DeviceActivityName(
            "GoalHabit-" + habit.id.uuidString
) 

let startInterval = DateComponents(hour : 0, minute : 0) 
let endInterval = DateComponents(hour : 23, minute : 59) 
let schedule =  DeviceActivitySchedule(
            intervalStart: startInterval,
            intervalEnd: endInterval,
            repeats: true
)
  do{
     try deviceActivityCenter.startMonitoring(
            deviceActivityName,
            during: schedule,
            events: [deviceActivityEventName : deviceActivityEvent]
   )
   return true
 }catch {
     return false
}

deviceActivityEvent is an action to be performed after reaching the threshold

 override func eventDidReachThreshold(_ event: DeviceActivityEvent.Name, activity: DeviceActivityName) {
        super.eventDidReachThreshold(event, activity: activity)
let viewContext = PersistenceController.shared.container.viewContext
        let (year, month, day) = getYearMonthDay(.now)
        let newHabitRecord = HabitRecord(context: viewContext)
        newHabitRecord.id = UUID()
        newHabitRecord.habitId = id
        newHabitRecord.year = Int16(year)
        newHabitRecord.month = Int16(month)
        newHabitRecord.day = Int16(day)
        newHabitRecord.duration = middleValue * 60  // 当前思考的秒
        newHabitRecord.type = 0
        newHabitRecord.createDate = .now
        do {
            try viewContext.save()
            WidgetCenter.shared.reloadAllTimelines()
        }catch {
        }
}

I wish I knew why it failed。 My system has been upgraded to 18.3。

After upgrading the system last night, it failed again

About the problem that DeviceActivityMonitorExtension does not work
 
 
Q