Our app monitors device usage and applies a shield when the set time limit is reached. Multiple DeviceActivitySchedules can be present, each with different time limits. To display notifications at 50% of the total limit for each DeviceActivitySchedule, we set a warning time at half of the total time. However, we occasionally receive premature event callbacks.
For example, consider a schedule from 13:00 to 13:30 with a single event threshold at 10 minutes and a warning time of 5 minutes. The 'eventDidReachThreshold' callback is delivered prematurely, along with the 'eventWillReachThresholdWarning' callback, at 13:10.
Additionally, in some cases, when one DeviceActivitySchedule ends and the next begins immediately, DeviceActivityEvents registered for the new DeviceActivitySchedule are delivered prematurely along with the schedule start callback.
For example, consider there are two DeviceActivitySchedules from 12:00 to 13:00 and from 13:00 to 14:00, each with a limit of 10 minutes and a warning time of 5 minutes. When the first schedule ends and the next begins at 13:00, the 'eventDidReachThreshold' callbacks for the events registered in the second schedule are delivered prematurely, along with the 'intervalDidStart' callback.
Screen Time
RSS for tagShare and manage web-usage data, and observe changes made to Screen Time settings by a parent or guardian.
Posts under Screen Time tag
160 Posts
Sort by:
Post
Replies
Boosts
Views
Activity
Hi all,
For context, the Family Controls entitlement request (for the Personal Device Management category/individual use case) includes the question:
Will your app share device or usage data beyond the individual for the individual use case, or Family Sharing for the parent/guardian use case, including through means such as screenshots, screen recordings, or server logging?
I'm looking for clarification on how to interpret this. I originally answered Yes and was rejected, then later answered No and was accepted.
Ideally, I would like my screen time management app to allow users to opt-in to social features. One simple example is opting into a leaderboard with your friends for who has the lowest screen time.
If the user installed this app for themself and chooses to share this basic data with their friends, it sounds like an ethical and unproblematic feature but I suppose storing that data would fall under "server logging"?
If anyone has any experience with this, I would appreciate a more explicit description of the requirement above. Is what I described allowed?
Thanks for reading!
Hello community:
Is there any way to change the button color of the screen time permission to match app style?
When I upgraded to iOS 18 beta, I don’t recall setting a screen time passcode, however one is set. I am locked out from changing the passcode. I have clicked “forgot passcode” down at bottom but it doesn’t do anything. I am the only user on this phone. I am currently running iOS iOS 18.2 (22C5125e). Please advise, as screen time is locked and cannot be viewed nor change passcode
The data displayed about a child’s apps can be outdated (DeviceActivityReport), leading to misinformation for the user. When I access the “Screen Time” section (for child in the parent device) in the iPhone settings, I see there is an update functionality to force load the actual data.
I have tried various workarounds, such as attempting to force an update on the child’s device to call DeviceActivityReport and opening system settings, but none of these have been successful :(
How can I implement something similar? Is there a way to force update this data ?
I’ve updated to iOS 18.1 public beta when it released and I got the problem when I was in public beta 4 to rc and the problem never fixed with the time limit when I ask for more time it never give me more time it’s just says waiting for parent approval I have this problem until ios 18.1 RC can u fix it I’m on iPhone 11 pro max
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.
}
}
I need some assistance with the Screen Time API’s DeviceActivityReport extension. I know the extension is sandboxed but I need the data inside my app. Jomo is currently doing this so it’s not impossible. I see they’re saying it’s an estimate which is about 5 - 10 off of the actual screen time, but how are they doing this?
Any attempt to store the screen time data inside some sort of database or UserDefaults always fails of course due to the sandbox.
Any advice would be greatly appreciated!
Hello, I'm currently facing some technical difficulties in implementing features related to application restrictions using the ScreenTime API.
In our app, we allow users to set up restrictions for specific apps and app categories, with scheduled times and days (for example, Mondays and Thursdays, from 2pm to 5pm). The blocking sessions must run independently and simultaneously, allowing different sets of applications to be restricted at different times. However, I ran into two main problems:
1. Applying restrictions in the DeviceActivityMonitor extension:
Although I can enable and disable restrictions, I haven't found an effective way to apply multiple FamilyActivitySelections directly in the DeviceActivityMonitor extension. The extension has to manage different blocking sessions independently, restricting different sets of applications and categories simultaneously or separately.
I would like to know if it is possible to transmit this list of selected applications via UserDefaults or CoreData to the extension in order to facilitate this integra
To better illustrate, here is a snippet of the code I am using:
import Foundation
import FamilyControls
import ManagedSettings
import DeviceActivity
class AppBlockManager: ObservableObject {
private let store = ManagedSettingsStore()
private let center = DeviceActivityCenter()
@Published var activitySelection: FamilyActivitySelection
private var activityName: DeviceActivityName
private var schedule: DeviceActivitySchedule
init(selection: FamilyActivitySelection, activityName: DeviceActivityName, schedule: DeviceActivitySchedule) {
self.activitySelection = selection
self.activityName = activityName
self.schedule = schedule
}
func startBlock() {
do {
try center.startMonitoring(activityName, during: schedule)
if let applications = activitySelection.applications.isEmpty ? nil : activitySelection.applicationTokens {
store.shield.applications = applications
}
if let categories = activitySelection.categories.isEmpty ? nil : activitySelection.categoryTokens {
store.shield.applicationCategories = ShieldSettings
.ActivityCategoryPolicy
.specific(categories)
store.shield.webDomainCategories = ShieldSettings
.ActivityCategoryPolicy
.specific(categories)
}
if let webDomains = activitySelection.webDomains.isEmpty ? nil : activitySelection.webDomainTokens {
store.shield.webDomains = webDomains
}
} catch {
print("Error starting monitoring: \(error)")
}
}
func stopBlock() {
store.shield.applications = nil
store.shield.webDomains = nil
store.shield.applicationCategories = nil
store.shield.webDomainCategories = nil
center.stopMonitoring([activityName])
}
}
Currently, this AppBlockManager is part of the main app target, not within the DeviceActivityMonitor extension, which is currently empty. With this configuration, I can only have one blocking session active at a time, and when it is deactivated, all restrictions are removed. I tried using different ManagedSettingsStore instances, each named individually, but without success.
2. Problems with scheduling restrictions:
Currently, when setting up scheduled monitoring via DeviceActivitySchedule, the restrictions are activated immediately, ignoring the specific times scheduled (e.g. starting at 2pm and ending at 5pm). I need the schedule to work correctly, applying the restrictions only during the defined periods.
Alternatively, I've considered running a background task that checks whether active sessions (up to a maximum of 3) should apply the restrictions at that time, but I'm still looking for a more suitable solution.
In view of these challenges, I would like some guidance on the following points:
What would be the best way to configure the DeviceActivityMonitor extension to receive and apply different FamilyActivitySelections, ensuring that the blocking sessions are independent and can run simultaneously?
Is there a recommended approach to ensure that restrictions scheduled via DeviceActivitySchedule are applied and removed according to the times and days defined by the user, ensuring that applications are restricted only during the scheduled periods?
ActivityCategoryPolicy.all(except: allowList) blocks all apps, even the ones that should be exempted
Hello fellow Screen Time developers!
I have bee experimenting with the ActivityCategoryPolicy.all(except: allowList) API of the ManagedSettings framework in order to provide a digital detox feature to my app, where ALL apps would be blocked, except some important ones (phone, messages, maps).
The apps to be exempted can be configured by the user via the FamilyActivitySelection().
However, I am experiencing a strange bug, where all apps are restricted / blocked, even the ones that are set to be exempted and are part of the allowList Set.
Instead of not restricting allowed apps at all, these apps are restricted with a generic shield (screenshot below) – a concrete shield is not requested for them from my ShieldConfigurationDataSource.
I have also filed a radar under this number, attached is a minimalistic sample project and video that shows how to reproduce this: FB15500605
(no response so far)
I have also seen other people report on this issue, but couldn't find any useful information there:
https://forums.developer.apple.com/forums/thread/750988
https://forums.developer.apple.com/forums/thread/762287
Thanks a lot for your help, and have a nice day!
Why is my screen time doing this??? I’ve literally been on my phone about 30 mins today but it’s saying I’ve been on it all night. but it’s all grey lines and I can’t look at what it is?
Hello,
I think it is quite a common use-case to open the parent app that owns the ShieldActionDelegate when the user selects an action in the Shield.
There are only three options available that we can do in response to an action:
ShieldActionResponse.none
ShieldActionResponse.close
ShieldActionResponse.defer
It would be great if this new one would be added as well:
ShieldActionResponse.openParentApp
While finding a workaround for now, the problem is that the ShieldActionDelegate is not a normal app extension. That means, normal tricks do not work to open the parent app from here.
For example, UIApplication.shared.open(url) does not work because we can’t access UIApplication from the ShieldActionDelegate unfortunately.
NSExtensionContext is also not available in the ShieldActionDelegate unfortunately, so that’s also not possible.
There are apps however, that managed to find a workaround, in my research I stumbled across these two:
https://apps.apple.com/de/app/applocker-passcode-lock-apps/id1132845904?l=en-GB
https://apps.apple.com/us/app/app-lock/id6448239603
Please find a screen recording (gif) attached.
Their workaround is 100% what I’m looking for, so there MUST be a way to do so that is compliant with the App Store guidelines (after all, the apps are available on the App Store!).
I had documented my feature request more than 2 years ago in this radar as well: FB10393561
Hello
I updated my iPhone 13 to iOS 18 a few days ago and the last two nights, it indicated that my screen was on whilst I had actually switched my phone off for the night.
Last night I made sure to close all apps before I switched it off but Screen Time still says that my screen was on.
Is there a way to fix this so as to have screen time that actually corresponds to my screen time?
I’ve seen other users experiencing the same problem but haven’t found a solution.
Thanks!
Hello fellow Screen Time Fans!
I am encountering a strange problem since I started working with the Screen Time framework, and I don’t know what I’m doing wrong:
Imagine the app has two ManagedSettingsStores:
one to block apps during work hours (let’s say from 9am to 5pm) and one to block apps in the evening (let’s say from 5:30pm till midnight).
Imagine, the user has blocked Instagram in both.
When the user has Instagram open at 4:59pm it shows the Block during Work Hours Shield (so far, so good).
At 5pm, the shield is removed, and the user can use Instagram.
Then, at 5:30 the a shield is activated again: this time, the Instagram token is added to the evening store.
However, there is no new ShieldConfiguration requested from the ShieldConfigurationDataSource.
Instead, the previous shield from the work hour block is re-used and shown.
To me, it appears that the Framework does not request new shields, when the token is moved from one store to another while the app remains in foreground.
The Shield is only re-rendered when the user closes the shielded app and re-opens it.
This is really confusing behavior and I would like to fix it.
Did anyone here encounter something similar, and has a suggestion or workaround?
My feedback is also documented in FB14237883.
Core Data not returning results in ShieldConfiguration Extension, but works fine in other extensions
Hi everyone,
I’m using Core Data in several extensions (DeviceActivityMonitor, ShieldAction, and ShieldConfiguration). It works perfectly in DeviceActivityMonitor and ShieldAction. I’m able to successfully fetch data and log the correct count using a fetch request.
However, when I try the same setup in the ShieldConfiguration extension, the fetch request always returns 0 results. The CoreData and App Group setup appears to be correct since the first two extensions fetch the expected data.
I’ve also previously tested storing the CoreData objects separately in a JSON-FIle using FileManager and it worked without issues—though I’d prefer not to handle manual encoding/decoding if possible.
The documentation mentions that the extension runs in a sandbox, restricting network requests or moving sensitive content. But shouldn’t reading data (from a shared App Group, for instance) still be possible within the sandbox, as it is the case with the Files, what is the difference there? In my case, I only need to read the data, as modifications can be handled via ShieldActionExtension.
Any help would be greatly appreciated!
Hi, I noticed that all my apps are sometimes blocked even if I don’t have set up screen time for them. How can I fix it?
I use a parental control app and it should block apps only if I enable child mode, but after the iOS 18 update, it blocks apps even when I am still in parent mode.
Family activity picker looses icon and incudes parent apps after 20 seconds...and you never see the kids icons again until you reboot. Any ideas?
family controls authorized on both apps
Share across devices activated
Web & activity activated.
Before...
...and after 22 seconds.
A few weeks ago, I submitted a request for the Family Controls & Personal Device Usage Entitlement to enable my app to access the Managed Settings and Device Activity frameworks in the Screen Time API. The app is nearly complete, with the only remaining component being the Family Controls capability.
As of now, I haven’t received a response regarding the request. I’m wondering if anyone else has experienced a similar situation or can provide insight into the following:
• How long does it typically take to receive feedback on this type of entitlement request?
• Is there a way to check if a request is still active and under review?
• Is a finished website required for the entitlement to be granted?
Any information or guidance would be greatly appreciated!
Tl:dr What are some reasons my bundleIDs aren't showing up and does anyone have good resources to setup the screentime API/DeviceActivityMonitorExtension?
I'm working on an iOS app that uses the FamilyControls and DeviceActivity frameworks to monitor and restrict app usage. The app allows users to select apps and set usage limits. When a limit is reached, a DeviceActivityMonitorExtension should block the selected apps.
My App setup: Have a model that is called when users select apps to manage these app bundle IDs are then serialized and sent to the Device Monitor Extension via App Group so it can be used when the event threshold is reached. Cant use Application Tokens because they are not serielizable and cant be passed to the extension.
Problem: While testing, I’m unable to retrieve the bundleIdentifier and localizedDisplayName from the Application objects after selecting apps. Instead, these properties are nil or empty, preventing me from saving the bundle IDs to share with the extension via App Groups.
Assumptions: I suspect this issue is due to missing the com.apple.developer.screentime.api entitlement, which might be required to access these properties even during development. I've requested for the entitlement but its still under review.
Key Code Snippets:
Authorization Request:
class ScreenTimeManager: ObservableObject {
static let shared = ScreenTimeManager()
@Published var isAuthorized: Bool = false
func requestAuthorization() async {
do {
try await AuthorizationCenter.shared.requestAuthorization(for: .individual)
DispatchQueue.main.async {
self.isAuthorized = AuthorizationCenter.shared.authorizationStatus == .approved
print("Authorization status: \(AuthorizationCenter.shared.authorizationStatus)")
}
} catch {
DispatchQueue.main.async {
print("Authorization failed: \(error.localizedDescription)")
self.isAuthorized = false
}
}
}
}
Accessing bundleIdentifier:
print("addAppGroup() Called")
let managedApps = selection.applications.compactMap { application -> ManagedApp? in
guard let token = application.token else {
print("No token for application: \(application)")
return nil
}
let app = Application(token: token)
print("New Application instance: \(app)")
guard let bundleID = app.bundleIdentifier, !bundleID.isEmpty else {
print("Bundle identifier is empty or nil for application: \(app)")
return nil
}
let displayName = app.localizedName ?? "Unknown App"
print("Processing application with bundleIdentifier: '\(bundleID)' and displayName: '\(displayName)'")
return ManagedApp(
bundleIdentifier: bundleID,
applicationToken: token,
localizedDisplayName: displayName
)
}
if managedApps.isEmpty {
print("No managed apps created. Exiting addAppGroup().")
return
}
// Continue with creating DeviceActivityEvent...
}
Logs - Shows application token but never bundleID or LocalizedDisplayname
Application(bundleIdentifer: nil, token: Optional(128 byte <TOKEN_PRESENT>), localizedDisplayName: nil)
What I've Tried:
Ensured Screen Time is enabled on the device.
Verified App Group configuration in both app and extension.
Checked that authorization is being requested and the status is .approved.
Cleaned and rebuilt the project.
Questions:
Is the com.apple.developer.screentime.api entitlement required to access bundleIdentifier and localizedDisplayName when using .individual authorization?
Is there a way to access these properties without the entitlement, or am I missing a configuration step?
Has anyone faced a similar issue and found a solution?
Lastly, is there a good place for additional resources on the screentime API??
Made a screen time password a little while ago and recently updated to ios 18. Went to turn it off and couldn’t remember the password. There was not forgot password option and now I’m on my like millionth attempt to guess the password.