The fact that you are specifying the .day
component from intervalEnd
is causing the threshold to fire immediately. When your app starts monitoring a schedule, the system will first check whether or not the schedule is currently "active". The way it does this is it tries to find the previous time the schedule started and ended. If the previous start time comes after the previous end time, then the system treats the schedule as "active" or "ongoing". Let's say that the current time is 1:00pm on Monday. Based on your snippet, the system will determine that the previous start time for the schedule was Sunday at 1:01pm and the previous end time was last Monday at 1:20pm. That means the schedule your app started monitoring has been active since Sunday at 1:01pm and will end at 1:20pm this Monday and will include all app usage that occurred between those two dates (which is why your threshold callback is being invoked immediately). In most cases, you probably want to keep the components for both the interval start and interval end parameters consistent.
TL;DR: If you remove .day
from the following line, you should get the behavior you're looking for:
Calendar.current.dateComponents([.day, .hour, .minute], from: intervalEnd)
The documentation mentions this behavior about ongoing or "active" schedules here (although it could admittedly be a little more detailed):
Important
If the current date falls in between intervalStart and intervalEnd, the system calls the intervalDidStart(for:) method immediately upon starting to monitor the activity. If the current date doesn’t fall in between intervalStart and intervalEnd, then intervalDidStart(for:) calls at the next date matching intervalStart.