eventDidReachThreshold is working as expected only when the app is in debug mode

As per our code, we have the apps to be shielded whenever the threshold is reached. According to this use-case, our code in DeviceActivityExtension looks something like:

override func eventDidReachThreshold(_ event: DeviceActivityEvent.Name, activity: DeviceActivityName) {
    super.eventDidReachThreshold(event, activity: activity)
    
    defaults?.setValue(event.rawValue, forKey: "appLimitEventName")
    defaults?.setValue(true, forKey: "appLimitReached")
    defaults?.synchronize()

   // using darwinNotificationCenter to trigger callback in the application 
    let darwinNotificationCenter = DarwinNotificationsManager.sharedInstance()
    darwinNotificationCenter.postNotification(withName: "nextAppLimitInitiated")
    
    // using Notifications to debug since print doesn't work
    scheduleNotification(with: "interval threshold reached")
  }

And in our application, we have the shielding logic in place,

init() {
    let darwinNotificationCenter = DarwinNotificationsManager.sharedInstance()
    darwinNotificationCenter.register(forNotificationName: "nextAppLimitInitiated"){
      print("callback received")
      let appLimitReached = self.defaults?.bool(forKey: "appLimitReached")
      let appLimitEventName = self.defaults?.string(forKey: "appLimitEventName")
      
      if appLimitReached ?? false, appLimitEventName != "" {
      // this sends the notification when callback is received
        self.scheduleNotification(with: "init start")
        self.defaults?.setValue(false, forKey: "appLimitReached")

        guard var dataArray = self.defaults?.array(forKey: "appLimitdataArray"), !dataArray.isEmpty else {
          return
        }

        let appLimitData = dataArray.first as! NSDictionary
        let appLimitKey = appLimitData["appLimitId"] as! String
        let data = self.getSchedule(key: appLimitEventName ?? "")

        if let appTokens = data?.applicationTokens {
          for token in appTokens {
            if !self.applicationTokens.contains(appTokens) {
              self.applicationTokens.insert(token)
            }
          }
        }
        
        self.store.shield.applications = self.applicationTokens
        self.store.shield.applicationCategories = ShieldSettings.ActivityCategoryPolicy.specific(self.categoryTokens, except: Set())
        
        dataArray.removeFirst()
        //dataArray.append(appLimitData)
        self.defaults?.set(dataArray, forKey: "appLimitdataArray")
        self.initiateMonitoring(initiateAgain: true)
        self.scheduleNotification(with: "init end")
      }
    }
  }

This works as expected for multiple App Limits but only when the device is connected to the Xcode. If we disconnect the device from Xcode/ stop application from Xcode/ try in release mode, the callback is not received from extension to the app/init block.

When the device is connected to Xcode, if the apps hit the threshold, they are shielded automatically. But if the device is disconnected/ app is in release mode, the apps are not shielded automatically even after the threshold is reached. It is shielded later only after opening our app once.

Please let me know if I'm doing anything wrong in receiving callback or in my shielding logic. If I need to place the shielding logic in the extension, please tell me how I can handle multiple appTokens.

Replies

Why not just move your logic that apply shielding into the monitor extension ? I believe the darwin notification is working only when the app is running, and the monitor extension will not wakeup your app if it's not running. In debug mode, application stay in the running state much longer, but not in release mode, app are suspended as soon as a user background them (if not playing audio or using gps).

  • @_lilpit thanks for the explanation on why Darwin notification is working only in debug mode. We have moved our shielding logic into the monitor extension and it works as expected. Thanks for responding

Add a Comment

@_lilpit is there a way to monitor multiple events/schedules concurrently? Running startMonitoring on the second event just overrides the previously created one, along with the appTokens selected for that event. So, creating a new event un-shields the previously selected app and starts monitoring the newly created one even if we give the event a unique name like :

let event = DeviceActivityEvent(
      applications: activitySelectionData!.applicationTokens,
      categories: activitySelectionData!.categoryTokens,
      threshold: DateComponents(minute: limitDuration)
    )
let eventName = DeviceActivityEvent.Name(<uniqueId>)

What is the best way to handle multiple events and schedules without having them interfere with each other? Also curious to know how to keep track of applicationToken for each event separately.