Device Activity Monitor

I'd like to block the apps selected in FamilyActivityPicker individually when a certain threshold is met.

For example, let's say the threshold is 15 minutes, and I want to block both Photos and Freeform. If I spend 15 minutes on Photos, Photos should be blocked. Then, if I spend 15 minutes on Freeform, Freeform should also be blocked.

Currently, only Photos gets blocked after 15 minutes, but Freeform does not. How can I fix this problem so that each app is blocked individually when its respective 15-minute threshold is met?

Thank you in advance

File 1 :


class GlobalSelection {
    static let shared = GlobalSelection()
    
    var selection = FamilyActivitySelection()

    private init() {}
}

extension DeviceActivityName{
  static let daily = Self("daily")
}

@objc(DeviceActivityMonitorModule)
class DeviceActivityMonitorModule: NSObject {
  
  private let store = ManagedSettingsStore()

  @objc
  func startMonitoring(_ limitInMinutes: Int) {
          
    let schedule = DeviceActivitySchedule(
      intervalStart: DateComponents(hour: 0, minute: 0),
      intervalEnd: DateComponents(hour: 23, minute: 59),
      repeats: true
    )
    
    let threshold = DateComponents(minute: limitInMinutes)
    
    var events: [DeviceActivityEvent.Name: DeviceActivityEvent] = [:]
    
    // Iterate over each selected application's token
    for token in GlobalSelection.shared.selection.applicationTokens {
        // Create a unique event name for each application
        let eventName = DeviceActivityEvent.Name("dailyLimitEvent_\(token)")
        
        // Create an event for this specific application
        let event = DeviceActivityEvent(
            applications: [token],  // Single app token
            threshold: threshold
        )
        
        // Add the event to the dictionary
        events[eventName] = event
    }
        
    // Register the monitor with the activity name and schedule
    do {
      try DeviceActivityCenter().startMonitoring(.daily, during: schedule, events: events)
      print("24/7 Monitoring started with time limit : \(limitInMinutes) m")
      
    } catch {
        print("Failed to start monitoring: \(error)")
    }
  
    
  }
  
  @objc
  static func requiresMainQueueSetup() -> Bool {
    return true
  }
}

FIle 2 :


class DeviceActivityMonitorExtension: DeviceActivityMonitor {
  
    let store = ManagedSettingsStore()
  var blockedApps: Set<ApplicationToken> = []
  
  
    func scheduleNotification(with title: String) {
        let center = UNUserNotificationCenter.current()
        center.requestAuthorization(options: [.alert, .sound, .badge]) { granted, error in
            if granted {
                let content = UNMutableNotificationContent()
                content.title = "Notification" // Using the custom title here
                content.body = title
                content.sound = UNNotificationSound.default
                
                let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 5, repeats: false) // 5 seconds from now
                
                let request = UNNotificationRequest(identifier: "MyNotification", content: content, trigger: trigger)
                
                center.add(request) { error in
                    if let error = error {
                        print("Error scheduling notification: \(error)")
                    }
                }
            } else {
                print("Permission denied. \(error?.localizedDescription ?? "")")
            }
        }
    }
  
    // Function to retrieve selected apps
    func retrieveSelectedApps() -> FamilyActivitySelection? {
        if let sharedDefaults = UserDefaults(suiteName: "group.timelimit.com.zerodistract") {
            // Retrieve the encoded data
            if let data = sharedDefaults.data(forKey: "selectedAppsTimeLimit") {
                // Decode the data back into FamilyActivitySelection
                let decoder = JSONDecoder()
                if let selection = try? decoder.decode(FamilyActivitySelection.self, from: data) {
                    return selection
                }
            }
        }
        return nil // Return nil if there was an error
    }
  
    override func intervalDidStart(for activity: DeviceActivityName){
        super.intervalDidStart(for: activity)
        scheduleNotification(with: "Interval did start")
        scheduleNotification(with: "\(retrieveSelectedApps())")
    }
    
    override func intervalDidEnd(for activity: DeviceActivityName) {
        super.intervalDidEnd(for: activity)
    }
    
  override func eventDidReachThreshold(_ event: DeviceActivityEvent.Name, activity: DeviceActivityName) {
      super.eventDidReachThreshold(event, activity: activity)

      // Notify that the threshold is met
      scheduleNotification(with: "Threshold met")
      
      // Retrieve the selected apps
      if let selectedApps = retrieveSelectedApps() {
          // Extract the app token identifier from the event name
          let appTokenIdentifier = event.rawValue.replacingOccurrences(of: "dailyLimitEvent_", with: "")
          
          // Iterate over the selected application tokens
          for appToken in selectedApps.applicationTokens {
              // Convert the app token to a string representation (or use its debugDescription)
              let tokenString = "\(appToken)"
              
              // Check if the app token matches the token identifier in the event name
              if tokenString == appTokenIdentifier {
                
                blockedApps.insert(appToken)
                // Block only the app associated with this event
                store.shield.applications = blockedApps
                scheduleNotification(with: "store.shield.applications = blockedApps is reached")
                break
              }
          }
      } else {
          scheduleNotification(with: "No stored data for selectedAppsTimeLimit")
      }
  }
    override func intervalWillStartWarning(for activity: DeviceActivityName) {
        super.intervalWillStartWarning(for: activity)
        
        // Handle the warning before the interval starts.
    }
    
    override func intervalWillEndWarning(for activity: DeviceActivityName) {
        super.intervalWillEndWarning(for: activity)
        
        // Handle the warning before the interval ends.
    }
    
    override func eventWillReachThresholdWarning(_ event: DeviceActivityEvent.Name, activity: DeviceActivityName) {
        super.eventWillReachThresholdWarning(event, activity: activity)
        
        // Handle the warning before the event reaches its threshold.
    }
}
Device Activity Monitor
 
 
Q