The listening callbacks were not triggered for intervalDidStart and intervalDidEnd after successfully starting center.startMonitoring when I attempted to set a schedule with DeviceActivitySchedule at 20-minute intervals
Is there anyone who can assist me? Thank you.
Below you will find my code.
let intervalLengthInSeconds = 20 * 60
let intervalEnd = Date(timeIntervalSinceNow: TimeInterval(intervalLengthInSeconds))
let intervalStart = Date()
let schedule = DeviceActivitySchedule(intervalStart: Calendar.current.dateComponents([.hour, .minute], from: intervalStart),
intervalEnd: Calendar.current.dateComponents([.hour, .minute], from: intervalEnd),
repeats: false,
warningTime: DateComponents(minute: 1))
let newActivity = DeviceActivityName(rawValue: "20minuteUse")
Log("😯 \(String(describing: schedule.nextInterval))")
do {
try center.startMonitoring(newActivity, during: schedule)
} catch {
print("failed to start session: \(error.localizedDescription)")
}
class MyMonitorExtension: DeviceActivityMonitor {
let store = ManagedSettingsStore()
// You can use the `store` property to shield apps when an interval starts, ends, or meets a threshold.
override func intervalDidStart(for activity: DeviceActivityName) {
super.intervalDidStart(for: activity)
// Shield selected applications.
Log("😓 start-------")
}
override func intervalDidEnd(for activity: DeviceActivityName) {
super.intervalDidEnd(for: activity)
Log("😓 end-------")
}
override func intervalWillStartWarning(for activity: DeviceActivityName) {
super.intervalWillStartWarning(for: activity)
Log("😓 StartWarning-------")
}
override func intervalWillEndWarning(for activity: DeviceActivityName) {
super.intervalWillEndWarning(for: activity)
Log("😓 EndWarning-------")
}
}
schedule.nextInterval ------ print:
😯 Optional(2024-06-21 08:34:00 +0000 to 2024-06-21 08:54:00 +0000)
Family Controls
RSS for tagPrevent access to the Screen Time API without guardian approval and provide opaque tokens that represent apps and websites.
Posts under Family Controls tag
184 Posts
Sort by:
Post
Replies
Boosts
Views
Activity
let schedule = DeviceActivitySchedule(
intervalStart: DateComponents(calendar: Calendar.current ,hour: 20, minute: 0), intervalEnd: DateComponents(calendar: Calendar.current ,hour: 22, minute: 59), repeats: true, warningTime: nil
)
store.shield.applications = selectionToDiscourage.applicationTokens.isEmpty ? nil : selectionToDiscourage.applicationTokens
store.shield.applicationCategories = selectionToDiscourage.categoryTokens.isEmpty ? nil : ShieldSettings.ActivityCategoryPolicy.specific(selectionToDiscourage.categoryTokens)
store.shield.webDomains = selectionToDiscourage.webDomainTokens
store.application.blockedApplications = selectionToDiscourage.applications
try center.startMonitoring(.daily, during: schedule)
try center.startMonitoring(.daily, during: schedule)
let schedule = DeviceActivitySchedule(
intervalStart: DateComponents(calendar: Calendar.current ,hour: 20, minute: 0), intervalEnd: DateComponents(calendar: Calendar.current ,hour: 22, minute: 59), repeats: true, warningTime: nil
)
extension DeviceActivityName {
static let daily = Self("daily")
}
So I updated my phone to ios18 beta and ever since then my phone will always crash when I enter screen time but any other application nothing will happen, my phone has gotten so much slower and heats up faster. Lags so much! I dont know what else to do. I have 107gb and my max is 128gb so I don’t see that as the issue. Especially since I can’t enter into my screen time. I waited it out for almost two or one week. it hasn’t changed. restarted my phone and everything. please help asap!!!
Actually, I'm developing a new app based on screen time API, so I implemented my report device extension like this
struct TotalActivityReport: DeviceActivityReportScene {
// Define which context your scene will represent.
let context: DeviceActivityReport.Context = .totalActivity
// Define the custom configuration and the resulting view for this report.
let content: (ActivityReport) -> TotalActivityView
func makeConfiguration(representing data: DeviceActivityResults<DeviceActivityData>) async -> ActivityReport {
// Reformat the data into a configuration that can be used to create
// the report's view.
var res = ""
var list: [AppDeviceActivity] = []
let totalActivityDuration = await data.flatMap { $0.activitySegments }.reduce(0, {
$0 + $1.totalActivityDuration
})
for await d in data {
res += d.user.appleID!.debugDescription
res += d.lastUpdatedDate.description
for await a in d.activitySegments{
res += a.totalActivityDuration.formatted()
for await c in a.categories {
for await ap in c.applications {
let appName = (ap.application.localizedDisplayName ?? "nil")
let bundle = (ap.application.bundleIdentifier ?? "nil")
let duration = ap.totalActivityDuration
let numberOfPickups = ap.numberOfPickups
let token = ap.application.token
let app = AppDeviceActivity(
id: bundle,
displayName: appName,
duration: duration,
numberOfPickups: numberOfPickups,
token: token
)
list.append(app)
}
}
}
}
return ActivityReport(totalDuration: totalActivityDuration, apps: list)
}
}
Then TotalActivityView to visualize returned data like this
//
// TotalActivityView.swift
// DemoScreenTimeReporter
//
// Created by Achraf Trabelsi on 17/06/2024.
//
import SwiftUI
import ManagedSettings
struct TotalActivityView: View {
var activityReport: ActivityReport
var body: some View {
VStack {
Spacer(minLength: 50)
Text("Total Screen Time")
Spacer(minLength: 10)
Text(activityReport.totalDuration.stringFromTimeInterval())
List(activityReport.apps) { app in
ListRow(eachApp: app)
}
}
}
}
struct ListRow: View {
var eachApp: AppDeviceActivity
var body: some View {
HStack {
Text(eachApp.displayName)
Spacer()
Text(eachApp.id)
Spacer()
Text("\(eachApp.numberOfPickups)")
Spacer()
Text(String(eachApp.duration.formatted()))
if let appToken = eachApp.token {
Label(appToken).labelStyle(.iconOnly)
}
}
}
}
But I got this issue : Cannot convert value of type 'ApplicationToken' (aka 'Token') to expected argument type 'LabelStyleConfiguration'
So if anyone have an idea, how can we get application icons please ?
My app allows users to select apps and websites to block using the Screen Time API. Lately I have gotten a bunch of emails from users who say that selecting one app also results in other apps of that family being blocked, even if they aren't selected in the FamilyActivityPicker.
The most common example is Facebook. A handful of users have said that they selected Facebook to be blocked, but Messenger will be blocked as well (even though Messenger isn't selected, and they don't want it to be blocked).
Does anyone know why this might be happening? It seemed to begin happening awhile ago after allowing users to block websites in addition to apps - not sure if that could have something to do with it.
I have experienced a consistent bug with screen time in IOS 18 DB1. It just doesn’t work, but the limits still function. I cannot access screen time settings (it just crashes) nor can I disable screen time from within a blocked app itself. Have not found any workaround.
I have logged a feedback report, FB13932765 (Unable to open screen time settings, it just crashes)
I Hope this can be looked at and resolved by the next update.
Thanks,
Felix
We are using the Apple ScreenTime API for monitoring the usage of device. As mentioned in the documentation (https://developer.apple.com/documentation/familycontrols), we are getting the family controls authorisation from the user. We also have added the ‘DeviceActivityMonitor’ app extension (https://developer.apple.com/documentation/deviceactivity/deviceactivitymonitor) to receive the schedule and event callbacks.
We have a requirement in which we have to notify the user for every 15 minutes usage of the device in the specified interval. He can optionally select individual categories or applications for the 15 minutes notification. For monitoring the usage for individual categories or applications, we obtain the token by presenting the FamilyActivityPicker as discussed in this documentation https://developer.apple.com/documentation/familycontrols/familyactivitypicker.
For simplicity in testing during the development phase, we reduced the 15 minutes to 2 minutes. The events callbacks are expected to be delivered as soon as the threshold is reached but there are some inconsistencies with the event threshold callbacks. Sometimes the event callbacks are deferred and delivered together, sometimes the event callbacks are not delivered at all, sometimes a few event callbacks are missed etc.
Brief & History
Since iOS 17.4 and up we experience a lot of flakyness when it comes to DeviceActivity event thresholds. After a lot of testing and investigations inside system logs and filing countless bug reports we found a reproducible way why the event thresholds are not getting properly called.
Findings
Apparently when the device reaches near to max memory something called jetsamkills processes left and right.
This means that the UsageTrackingAgent that (we think) is responsible for tracking the usage time of the device gets killed and doesn't recover until significant memory is freeing up on the device.
How to test it yourself
Use a slightly older device with ~ 3 or 4 GB of RAM
Open a game or two that is meomry intensive (like Fishing Clash, yes..) and observe
In the console logs you see something that only happens then:
Process UsageTrackingAgent [39307] killed by jetsam reason highwater
This happens often but recovers itself when the UsageTrackingAgent exceeds their 6MB memory limit. Yet the log looks like this:
Process UsageTrackingAgent [39307] killed by jetsam reason per-process limit
Once you kick the game, the memory is free and sometimes the event thresholds are calling in again.
Defeating the purpose
However this defeats the purpose of tracking usage time and shielding perhaps the playing app from being played after a certain amount of time!
Feedback Assistant Ticket
Here is the ticket with sysdiagnose, step by step and more information: FB13884981
Please fix this ASAP, this is such a pain for production users and their kids EVERY DAY.
Hello,
I want to make an app purely for academia to get the app usage data which includes timestamps of app usage and I want to store this data in a MySQL database for analysis purposes. From what I have read online, I don't get access to the raw data instead I can only see the data in Views. Is there any way I can export this data outside the app? Is it even possible?
With the ScreenTime API Apple talks a lot about their focus on privacy and the data not leaving the device. Does that mean there would be a problem with an app where the users ScreenTime data is shared to a custom backend? Could this potentially cause an app to be rejected from the AppStore?
Hi, I have a released screentime app ScreenZen. The last few days I've seen a disturbing spike in bug reports coming from people with 17.4.1 and 17.5.1 phones with no update to the app itself. People reported they saw the issue immediately after updating their iOS version. Unfortunately it is not replicable on all phones with those versions, so we haven't been able to replicate it on our test phones.
It appears the issue is the ApplicationToken passed into ShieldActionExtension and ShieldConfigurationExtension does not match any of the ApplicationTokens that the user selected to block through FamilyControls. (The selected ApplicationTokens are being loaded through a group UserDefaults and they are indeed being loaded in the ShieldActionExtension in the bug reports).This is preventing the app from loading the correct settings and handling the blocking accordingly. I am trying to isolate this better with a new release with better logging, but would appreciate any help on this issue.
I have a couple of questions on the FamilyActivityPicker that I couldn't seem to find in the documentation:
Is there any way to have it show only apps or websites? I've had some users reach out with frustrations because they want to select a category of apps (e.g. "Social"), but that also selects a lot of websites that they don't want to include.
Where does the picker get the websites that it populates? It seems like there's not much rhyme or reason to these (and there's often multiple urls for the same site - e.g. facebook.com and m.facebook.com).
Is there any way (as a developer) to have preset app selections available upon download? For example, can I have an option that has certain apps in the Social category chosen by default so that each user doesn't have to go in and manually select all of the apps they want?
我想通过 applicationToken 展示应用图标和应用名称,只查找到使用Label(applicationToken)来展示,但是展示的图标大小和图标名称字体,颜色均无法修改。是需要如何设置?还是需要其它方式来展示
Hello,
I developed a parental control app, this app has two clients one for the child and one for the parent. I could implement screen time to retrieve the child's screen time data and show it to the child by ActivityReportExtension but I didn't find any document to implement this feature on the parent device. I mean like the Apple screen time, parents can see their children's screen time (in the settings>screen time) I need to implement ActivityReportExtension in the parent client of my app that shows the child's screen time.
is it possible or this API is only restricted to Apple itself?
Hello,
I'm working on an app that makes use of Screen Time features by leveraging the Family Controls, Device Activity and Managed Settings frameworks.
The main app works fine by shielding/unshielding apps with a toggle.
When it comes to monitoring the time intervals with the Device Activity Monitor (DAM) extension (e.g. lock X apps for Y minutes), I'm experiencing several issues.
To shield/unshield apps and kick off the monitoring I perform the following instructions:
let timeInMinutes = 15
let startDate = Date(timeIntervalSinceNow: 1.0) // padding added to avoid invalid DAM ranges < 15 mins.
let endDate = startDate.addingTimeInterval(timeInMinutes * 60.0)
let components: Set<Calendar.Component> = [.day, .month, .year, .hour, .minute, .second]
let calendar = Calendar.current
let intervalStart = calendar.dateComponents(components, from: startDate)
let intervalEnd = calendar.dateComponents(components, from: endDate)
let schedule = DeviceActivitySchedule(intervalStart: intervalStart, intervalEnd: intervalEnd, repeats: false)
try deviceActivityCenter.startMonitoring(.definiteShield, during: schedule)
let managedSettingsStore = ManagedSettingsStore()
managedSettingsStore.shield.applications = selection.applicationTokens // `selection` being an instance of `FamilyActivitySelection`
The main pain points are:
After this code is performed, I would expect the Device Activity Monitor extension to start, or at least to start once I go to background. To check whether the DAM extension is running or not, I attach to the extension process manually (Product > Attach to Process by PID or Name). But I can see the extension correctly running only after 3-4 attempts of calling startMonitoring.
Even when the DAM extension runs, intervalDidStart and intervalDidEnd methods in the extension are called quite randomly - most of the times not being called at all - thus making the extension hugely unaffordable.
Please note:
I already ask for Screen Time permissions during the onboarding by calling AuthorizationCenter.shared.requestAuthorization(for: .individual), so by the time the user shields the apps, these permissions are already granted.
I already have Family Control entitlements for development and distribution, and for both the main target and the DAM extension target.
In the intervalDidEnd method, I simply call ManagedSettingsStore().clearAllSettings() and DeviceActivityCenter().stopMonitoring(). This looks like to be enough to stay way below the 6MB memory limit.
Am I doing something wrong, is there a way to fix this, or is just the Device Activity framework that is unstable?
Hi,
How to change title, subtitle, primaryButtonLabel, secondaryButtonLabel values according to iPhone language?
I noticed that the Shield Configuration Extension only runs once, when I turn on shield. Currently I can't find a way to run the Shield Configuration Extension again.
Thanks!
I am using the DeviceActivityMonitor eventDidReachThreshold functionality, but it became very unreliable on the iOS 17.5 beta.
Anyone experiencing similar problems?
Any known workarounds?
Hi there,
I'm currently working with the Screen Time API using the family controls package to manage application usage on iOS devices. I want to block access to all applications except those specifically allowed by the user. While the ManagedSettingsStore.shield.applications method works for defining apps to block. However, integrating the .all(except:) from ShieldSettings.ActivityCategoryPolicy.all(except:) is unfortunately not working for me.
Here is my code snippit. Can anyone help out? And if anyone has examples of similar implementations or tips on best practices for using the Screen Time API for such scenarios, please let me know!
class ShieldManager: NSObject, ObservableObject, NFCNDEFReaderSessionDelegate {
@Published var discouragedSelections = FamilyActivitySelection()
private let store = ManagedSettingsStore()
func shieldActivities() {
// Clear to reset previous settings
store.clearAllSettings()
// This is an array with the app and category selection
let applications = discouragedSelections.applicationTokens
let categories = discouragedSelections.categoryTokens
//
//https://developer.apple.com/documentation/managedsettings/shieldsettings/activitycategorypolicy
store.shield.applications = applications.isEmpty ? nil : applications
store.shield.applicationCategories = categories.isEmpty ? nil : .specific(categories)
store.shield.webDomainCategories = categories.isEmpty ? nil : .specific(categories)
}
f
I'm working on creating a locker app to lock the selected applications.
After locking app, when you try to open the app a screen appears with the below message.
Icon
Restricted
You can not use Facetime because it is restricted
OK Button.
How to customise this screen, another locker app is able to customise it and on a button click it redirects to their app to unlock it.
also is there a way to get locked app names?