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

Are you still having this issue?

About the problem that DeviceActivityMonitorExtension does not work
 
 
Q