Apple’s Screen Time API has some major issues

I’m Frederik and I’m the developer of the “one sec” app – which helps users to spend less time on social media.
For that reason, I’m heavily making use of Apple’s Screen Time frameworks: DeviceActivity
, ManagedSettings
, FamilyControls
.
As a developer, it’s not fun to work with these frameworks. While the original intentions of the API are great, many bugs exist that make my life hard. I try my best to work around all limitations, but unfortunately it’s not always possible.
In this blog post I’m summarizing some of the most prominent issues, hoping that my users get more understanding why features break sometimes.
And maybe there’s a chance that an Apple Engineer is reading this and hopefully this post gives them more context about which parts of the API need to be improved (I have indicated the feedback numbers alongside each problem).
How does the Screen Time API actually work
Apple’s approach to allow 3rd party apps manage screen time restrictions has a strong focus on privacy (which I like!): apps, such as one sec, don’t get any information on which target apps the user actually selects through FamilyActivitySelection
, all information is hidden behind cryptographic tokens.
Application tokens look like this:
{
"data": "AAAAAAAAAAAAAAAA0vp9A47itDEtRFJBo1qTIcnqhPUqGPgXo9lsfUwtJznfeI8C0/mKPRCpuJoazKFwo/RQg0gysx9Bpe/EId3yY7DeNlmHWM+fjpn9ZMsvPd6k76Mu3dmMv98QAKDKwNEKJv7aLjjfCnWVgP/8Y4SIe5RLjU8="
}
These app tokens can be used within SwiftUI Labels, to generate a user-facting display of the app’s name and icon, and they can be provided to a so-called ManagedSettingsStore
which will shield the app with an overlay.
Problem 1: Random Tokens (FB14082790)
Now that you know about the tokens, I can introduce you to the first major issue we see with the API:
From time to time, and without consistency, Screen Time suddenly provides new, random, unknown tokens to my app in the ShieldConfigurationDataSource
and ShieldActionDelegate
:
It’s basically like: hey, the app with token mb1b5nBgxUGv…
should be blocked, please provide the ShieldConfiguration
to shield the app!
Or: Hey, the user has pressed on the “Intervention” button in the Shield for the app with token mb1b5nBgxUGv…
. Do what should happen!
Problem is: For now reason, iOS decides to randomly change tokens sometimes. So it can happen that my app has never heard about a particular token before.
Then it does not know which group of tokens it belongs to, and it cannot check which ManagedSettingsStore
the app is actually blocked by – because in there, strangely the old tokens remain present.
So all in all, crucial context is missing: is this a Re-Interevntion? A Good Morning Countdown? A Block Session? A Block Schedule? A Focus Filter? No way to know!
There are many reasons why an app could be blocked by one sec – if a fresh, unknown token is provided to the Shield Confirguation Delegate there’s no way the code can determine the appropirate user interface.
…and it’s not only me, this issue has been reported as well by:
- Scott Harvey, ScreenZen App: https://forums.developer.apple.com/forums/thread/756440
- Thomas Maht, Jomo App: https://forums.developer.apple.com/forums/thread/758325
- Peter Schaeffer, Opal App: https://forums.developer.apple.com/forums/thread/758325?answerId=793267022#793267022
Problem 2: Moving Tokens from one ManagedSettingsStore
to Another (FB14237883)
My app one sec offers different paths to have target apps shielded:
- Re-Interventions
- Delayed Interventions
- Blocked by Focus Filter
- Recurring Blocks
- Manual Block Session
When a target app is removed from one block shield (e.g. a because a focus is turned off) and shortly atfer added to a different block shield (e.g. because a recurring block is starting), the shield UI is not updated, but the old focus block is re-used.
This is another issue which confuses users: because the UI shown by iOS is just wrong.
Problem 3: Unable to Lock Access to Screen Time Permissions for 3rd Party Apps (FB18794535)
Apple’s native Screen Time Settings can be locked with a passcode, different from the device passcode.
That means, a user can ask a friend or family member to set a passcode to ensure truly strict rules.
Unfortunately, that same functionality does not apply to 3rd party apps like one sec.
Even if Screen Time settings are locked with a passcode, Screen Time Permission to 3rd party apps can be easily revoked with a simple toggle in iOS settings.
Problem 4: Unable to Open Parent App (one sec) from Shield (FB15079668)
Many times, when a target app is blocked by a shield, the user wants to perform some action (e.g. to unlock more time for the target app via an intervention). An intervention can be a breathing exercise, or learning vocabulary.
That means, that somehow I have to forward the user from a ShieldActionDelegate
back into my target app.
Unfortunately, there’s no API for that.
Apple only allows three actions to be executed based on a button press:
.none
which does nothing..close
which returns to the home screen..defer
which re-loads theShieldConfiguration
.
It would be great if there was a fourth option .openParentApp
, or if we could simply run a URL scheme in order to open the parent app: UIApplication.openURL("onesec://")
.
This means that unfortunately, we have to implement quite stupid workarounds using local push notifications (which our users don’t really understand).
Sure, it works most of the time, but sometimes notifications get delayed by Apple Intelligence or blocked by a Focus.
Problem 5: Unable to Open Target App from an ApplicationToken
(FB15500695)
Related to Problem 4, in this section I would like to focus on the reverse use case:
When a user has completed an intervention within one sec, and they indend to to continue to the target app, there is no way that one sec can open the target app just from the token alone. Sure, there are URL schemes, but that means the user has to manually assign URL schemes to each ApplicationToken. That is not a very user friendly process (and in many cases impossible, because not every app registers URL schemes).
It would be better if there was a way that my app could open a target app directly from an ApplicationToken
, e.g. via an AppIntent that can be run on a button press. This way, the selected apps would remain fully private while still offering advanced functionality:
struct OpenTargetAppIntent: AppIntent, OpenAppFromApplicationTokenIntent {
func perform() {
return .result(openAppFromApplicationToken: applicationToken)
}
}
Thanks a lot for taking the time to read my feedback. If you have any questions, please feel free to reach out to me any time. I’m always happy to provide more details, logs, and steps to reproduce in my radars / feedback requests or in-person in Cupertino.
If you liked this article, you can follow me on Twitter and subscribe to my newsletter to stay up to date.