Hi folks!
Please help me to clarify some things related to Screen Time API.
What the keys differences between individual and child authorization? With individual type of auth user can do sign-out from iCloud and delete the app. What else differentiate this type of users?
Can we use DeviceActivityEvent for remote control with individual auth?
Can the parental or guardian see/get the statistic of apps usage?
Is the individual auth available to all users or just those who are in the Apple's family?
I'll really appreciate any help and answer! Thank you in advance!
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
148 Posts
Sort by:
Post
Replies
Boosts
Views
Activity
Hello! I believe there is a bug: ShieldConfigurationDataSource extension does not update when the app to be blocked is already open and the ManagedSettingsStore.shield.applications is set to the app that is already open. The shield comes up but has a stale ShieldConfiguration not reflecting the current state of the app is used.
I've been able to replicate the issue in an independent app "OffScreen". If you start a blocking time range from 10:00-10:15, it will say "No Twitter until 10:15" and then open Twitter at 10:15. If there is another blocking time range from 10:16-10:31, the app will be open until 10:16 when the shield will reactivate and it will still say "No Twitter until 10:15" when is should say "No Twitter until 10:31".
thanks!
When I tap on one of the buttons in the ShieldAction extension I want to close the shield and open the parent app instead of the shielded app. Is there any way of doing this using the Screen Time API?
class ShieldActionExtension: ShieldActionDelegate {
override func handle(action: ShieldAction, for application: ApplicationToken, completionHandler: @escaping (ShieldActionResponse) -> Void) {
// Handle the action as needed.
let store = ManagedSettingsStore()
switch action {
case .primaryButtonPressed:
//TODO - open parent app
completionHandler(.defer)
case .secondaryButtonPressed:
//remove shield
store.shield.applications?.remove(application)
completionHandler(.defer)
@unknown default:
fatalError()
}
}
}
There is frequently a delay of a few seconds before a DeviceActivityReport renders its view generated from the DeviceActivityReportExtension. It will also sometimes flash with zero data before hydrating with the real activity data (tested with extension code taken directly from XCode boilerplate)
Is there a way to be notified when the DeviceActivityReport renders successfully or is still processing, i.e. so a loading indicator can be presented while the extension runs?
Thanks!
Hello,
we have rare case of AuthorizationCenter.shared.requestAuthorization(for: .individual) failing to autorize user on real device - iPhone XR (iOS 16.1.2).
It does not throw the standard FamilyControlsError which we are handling, but NSCocoaErrorDomain.
This is the entire po description:
Error Domain=NSCocoaErrorDomain Code=4864 "The given data was not a valid property list." UserInfo={NSCodingPath=(), NSDebugDescription=The given data was not a valid property list., NSUnderlyingError=0x283af4d80 {Error Domain=NSCocoaErrorDomain Code=3840 "Cannot parse a NULL or zero-length data" UserInfo={NSDebugDescription=Cannot parse a NULL or zero-length data}}}
The localized one says:
"The data couldn’t be read because it isn’t in the correct format."
This sounds like some error deep in iOS. The testing device has Apple ID logged in and uses passcode.
Anything we can do on our end to solve this issue?
I am trying to build an app that blocks access to other apps (Like screentime) through react native. I know that IOS has ScreenTime API which has device activity which has the feather to do that. Is it possible to integrate this into a react native app?
I've been looking online but can't find much information or documentation regarding this, but I failed to find much.
currently when I try to set several schedules to the same activity the latest schedule I set is the only one
I understand I can have only 1 schedule for activity. ?
I thought about setting a new schedule on the intervalDidEnd but, I get no interval did start if the current time is in the middle of the interval I set
For example, now it is 15:00, and my previous interval started at 14:00 and ends at 16:00 but the user sets a new interval from 14:30 - 16:40
I call the deviceActivityCenter.stopMonitoring([someActivityName]) and get noIntervalDidEnd event
Then I set the new interval successfully with deviceActivityCenter.startMonitoring(someActivityName, during: deviceActivitySchedule)
and get no intervalDidStartEvent
So how can I achieve several intervals?
If I had gotten the events of the start and end it would be possible
Thanks for the help
Hi there,
In rare cases (about 0.2% of the time?), I'm seeing calls to startMonitoring on an instance of DeviceActivityCenter throw an error with localizedDescription "couldn’t communicate with a helper application."
I am certain I am passing valid parameters to the startMonitoring call because sometimes a naive retry after a few seconds succeeds. Similarly, I am certain that FamilyControls permissions have been granted by the user.
Was hoping to get more color from the systems team on what some causes of this error are and if it is avoidable by the programmer.
Hi, I’d like to access the source code for the demo app from whats new in screen time api. Can I get a copy of it through email or can you post it under sample code of wwdc 22 section?
I'm looking for a way to check user Screen Time and trigger a notification after a specified amount of time on certain apps. I have the code from WWDC21 but I was wondering if I could get the code sample for the Worklog app created for WWDC22.
Would really help as a reference point for building my project.
Thank you!
Hi,
I'm having trouble understanding what is the correct DateComponents format for the DeviceActivityCenter.startMonitoring to work as expected.
Here's how it behaves with my setup:
The schedule interval is set for 15 minutes (the minimum).
On intervalDidStart I set the shields
shield.applicationCategories = .all(except: exclCat)
shield.webDomainCategories = .all(except: exclWeb)
On intervalDidEnd I clear the settings
shield.applicationCategories = nil
shield.webDomainCategories = nil
Different behavior with different DeviceActivitySchedule intervals. In the below examples I'll refer to hour, minute and second components as time components, and the calendar, timeZone, year, month, day, hour, minute and second components as date and time components.
Also, with all combinations below no errors are thrown when calling the startMonitoring method.
A. ❌ The start interval has time components, while the end interval has date and time components:
The intervalDidStart is not triggered.
DeviceActivitySchedule(schedule: <USDeviceActivitySchedule: 0x28354a5e0>
IntervalStart: <NSDateComponents: 0x2839c7f40> {
Hour: 9
Minute: 24
Second: 55
IntervalEnd: <NSDateComponents: 0x2839c7f70> {
Calendar: <CFCalendar 0x2818f9090 [0x1e4fb1d10]>{identifier = 'gregorian'}
TimeZone: Asia/Manila (GMT+8) offset 28800
Calendar Year: 2023
Month: 5
Leap Month: 0
Day: 15
Hour: 9
Minute: 39
Second: 55
Repeats: 0
WarningTime: (null))
B. ❌ The start interval has date and time components, while the end interval has time components:
Here, the opposite of the above example happens — the intervalDidStart is triggered, but the intervalDidEnd is not.
C. ❌ Both intervals have time components:
The intervalDidStart is not triggered.
D. ✅ Only hour, minute, and second components for both start and end intervals:
Callbacks are called as expected.
DeviceActivitySchedule(schedule: <USDeviceActivitySchedule: 0x282e80450>
IntervalStart: <NSDateComponents: 0x2822f39f0> {
Hour: 9
Minute: 12
Second: 15
IntervalEnd: <NSDateComponents: 0x2822f3a00> {
Hour: 9
Minute: 27
Second: 15
Repeats: 0
WarningTime: (null))
So it seems that the correct and working version is with the time components only.
However, from the documentation, the maximum schedule interval is a week.
So if I need to set the schedule starting from a certain time of day A and ending in a certain time of day B, what should the DateComponents look like?
Thanks for you help!
Our app uses Cordova with a Cordova Local Webserver plugin. This plugin uses the url http://localhost: with a randomly chosen port. Some of the devices that our app runs on are MDM configured and have Content Filters enabled which only allows a finite list of website URLs to be accessed. This configuration has always worked in the past. Starting with the release of iPadOS 16.5, our app now hangs because the content filters are now preventing access to http://localhost. We've tried adding http://localhost, plus any derivative of that URL (i.e. http://localhost:, http://localhost:*, etc.) to the Allowed Website list, but this does not help.
Wondering if anyone else has encountered this issue.
We persist ApplicationTokens in a storage container that ShieldConfigurationExtension has access to. In rare, cases all the ApplicationTokens for a user seem to change.
We know this because the Application parameter passed into configuration(shielding application: Application) -> ShieldConfiguration function has a Token that does not match (using == ) any of the ones we are persisting in storage.
Interestingly, the persisted ones still work, so I don't believe storage has gotten corrupted or anything. We can use them to add or remove shields, we can use them to display labels of the apps they represent, etc. But they don’t match what’s passed into the ShieldConfiguration extension. If the user goes into the FamilyPicker at this point and selects an app of a token that we are already persisting, the FamilyPickerSelection will have a token matching the new one that is passed into ShieldConfigurationExtension, not the one we persisted when they last selected that app.
This leads me to believe the tokens are updated/rotated in some cases. When and why does this happen, and how can we handle it gracefully?
I'm having trouble with my DeviceActivityMonitorExtension. The intervalDidStart function is not being called when the scheduler is created. Does anyone have an idea why this is?
let schedule = DeviceActivitySchedule(
intervalStart: DateComponents(hour: 15, minute: 23),
intervalEnd: DateComponents(hour: 16, minute: 55),
repeats: true
)
class MySchedule {
static public func setSchedule() {
let center = DeviceActivityCenter()
center.stopMonitoring([.daily])
do {
try center.startMonitoring(.daily, during: schedule)
} catch {
print("Error monitoring schedule: ", error)
}
}
}
class DeviceActivityMonitorExtension: DeviceActivityMonitor {
override func intervalDidStart(for activity: DeviceActivityName) {
super.intervalDidStart(for: activity)
SelectedApps.shared.setRestrictions()
}
private let _SelectedApps = SelectedApps()
class SelectedApps: ObservableObject{
@Published var selection: FamilyActivitySelection
let store = ManagedSettingsStore()
init() {
if let savedSelection = UserDefaults.standard.object(forKey: "savedSelection") as? Data {
let decoder = JSONDecoder()
if let loadedSelection = try? decoder.decode(FamilyActivitySelection.self, from: savedSelection) {
selection = loadedSelection
} else {
selection = FamilyActivitySelection(includeEntireCategory: true)
}
} else {
selection = FamilyActivitySelection(includeEntireCategory: true)
}
}
class var shared: SelectedApps {
return _SelectedApps
}
func setRestrictions(){
let applications = selection
store.shield.applications = applications.applicationTokens.isEmpty ? nil : applications.applicationTokens
store.shield.applicationCategories = applications.categoryTokens.isEmpty
? nil
: ShieldSettings.ActivityCategoryPolicy.specific(applications.categoryTokens)
}
Hey everyone. My friend and I have an idea of creating an app that allows you to compete against others by seeing who can use certain apps the least. To do this, we need to get the statistics of every app's screen time usage.
I looked at doing this through the Screen Time API. However, it isn't very clear to me what app developers can access. Can we access a time breakdown of all apps' screen time usage (similar to the information in the Screen Time Settings screen)? If not, would the best route to manually implement our own tracking system? Thanks!
I am creating a custom shield UI for when an app is blocked. have an AppDelegate file where my @UIApplicationMain is run
I pasted in the ShieldConfiguration code from the WWDC21 Meet Screen Time demo inside my app:
class MyShieldConfiguration: ShieldConfigurationDataSource {
override func configuration(shielding application: Application) -> ShieldConfiguration {
return ShieldConfiguration(
title: ShieldConfiguration.Label(text: "Doxo", color: UIColor.blue),
subtitle: ShieldConfiguration.Label(text: "heyhey")
)
}
}
but after calling store.shield.applications = ....
the default restricted screen is being shown instead of the one I configured above
Where am I supposed to put MyShieldConfiguration ?
Context
I'm working on an iOS application that would use the Screen Time API and running into difficulties requesting authorization. This is for the user to manage their own screen time, not to be used with children account.
The Issue
I'm receiving a FamilyControls.FamilyControlsError error=3 when requesting authorization for .individual, when running the application in the simulator.
Also seeing The capability associated with "FAMILY_CONTROLS" could not be determined in Signing and Capabilities.
The simulator is logged into an account that has screen time enabled. The Family Controls capability has already been added. My entitlements file has Family Controls set to Yes.
Questions
(1) Should I be able to have this function in the simulator before my Family Controls request gets approved? I've only recently submitted the form, but I wouldn't think this is an issue during development.
(2) Might issues with the Provisioning Profile be the cause of this issue? Again, I'm only trying to get this to work in development/debug at the moment.
(3) What else would you recommend attempting to resolve this issue?
I'm fairly new to iOS programming, so any help and patience is really appreciated. Not sure where to go from here. I've looked through other potentially realted posts but have not found solutions to this problem. Thank you!
The steps are as follows:
1、AuthorizationCenter.shared.requestAuthorization(for: .individual) And grant permission
2、go to Settings , Cancel permission
3、Go back to the APP and query permissions,AuthorizationCenter.shared.authorizationStatus always Approved
/// let cancellable = center.$authorizationStatus
/// .sink() {
/// switch center.authorizationStatus {
/// case .notDetermined:
/// // Handle the change to notDetermined.
/// case .denied:
/// // Handle the change to denied.
/// case .approved:
/// // Handle the change to approved.
/// }
/// }
But when I went to set the change permissions,unable track changes to your app's authorization status
hi there,
i'm not sure if i'm missing something, but i've tried passing a variety of CGImages into SCSensitivityAnalyzer, incl ones which should be flagged as sensitive, and it always returns false. it doesn't throw an exception, and i have the Sensitive Content Warning enabled in settings (confirmed by checking the analysisPolicy at run time).
i've tried both the async and callback versions of analyzeImage.
this is with Xcode 15 beta 5.
i'm primarily testing on iOS/iPad simulators - is that a known issue?
cheers,
Mike