DEV Community

Cover image for What No One Tells You About Building with Apple’s Screen Time API
Nikki Eke
Nikki Eke

Posted on

What No One Tells You About Building with Apple’s Screen Time API

User privacy is a foundational priority in iOS. While building for device usage monitoring and control with Apple Screen Time API I quickly realized that this API was never designed to give third-party developers the same level of control Apple’s own native Screen Time has internally.

This decision shapes every part of the developer experience. From opaque tokens that prevent you from identifying your user’s apps to heavily restricted extensions with no network access. Building with this API exposes you to the different creative ways Apple keeps developers locked out in a bid to protect users privacy.

This made it very challenging for developers like me that tried to build really ambitious features; because to build certain control features you do need a level of access. So I had a lot of experiences like: starting out with a plan and changing it midway due to platform restrictions, spending a lot of time going in circles due to undocumented limitations, discovering that some features were easy to build in Android but are simply impossible on iOS.

In this article I will be sharing my experience building with this API, observations made, lessons learnt, some workarounds I used and what is currently obtainable with Screen Time API at the time of writing this. If you are planning to build with this API, already building with it or simply curious, then you should read this.

What is Apple’s Screen Time API and What Does It Do?

Apple's Screen Time API is a set of tools that allows developers to create third-party apps for parental controls, digital wellness, or productivity. It enables apps to monitor device usage, track time spent on specific apps or websites, and enforce usage restrictions.

This API is very recent as it was only introduced in WWDC 2021. Prior to this, many developers built screen time features using MDM and/or VPN. When Apple discovered that MDM gave developers unilateral access to user information - as you can expect they removed most of those apps from the store and then introduced this API as an alternative. The aim was to protect user data whilst giving developers the platform they need to build their own screen time and device control features.

The Apple Screen Time API comprises of three distinct frameworks that allow developers build features that implement screen time and device usage control features natively on a device.

These are the three frameworks in the Apple Screen Time API:

FamilyControls (The Gateway)

Family Controls is the gateway, as it allows the user authorize access to Screen Time for your app.

The Family Controls framework leverages on Family sharing so that access to screen time can only be authorized by the guardian of a child in a family sharing group or the owner of the device. Once it has been authorized by a guardian, the child will be unable to delete your app without guardian approval.

Family Controls also allows users choose which apps or websites they want to control through your app. It does this through the Family Activity Picker. When the user makes a selection, it returns an opaque token that only the device can identify as the app or website selected. This means your app would never know which apps were selected by the user. This information remains strictly with Apple and the user.

Before you can use any of the APIs exposed for managing screen time you need to enable the Family Controls entitlement for both development and production (Testflight & Appstore Release). With the development entitlement you can complete your app development but to release the app you need the production entitlement.

This entitlement has to be specially requested for, through the Account holder of your Apple developer account. It has to requested for the main app and every single extension you’ll need for development. Review time takes any time from a few days to over three weeks and in bad cases a few months. Only when it’s approved can you then release for production, so it is wise to request for the production entitlement as early as possible. If you attempt to release the apps without approval, the APIs simply wouldn’t work.

ManagedSettings (The Enforcer)

ManagedSettings is the enforcer. It enforces all the restriction and control features you have set up, like: blocking apps, shielding apps, preventing password change, filtering web traffic and a host of others.

Through the ManagedSettingsUI you can also style how the blocked content visually appears to your users, like the shield screen UI and the custom messages shown to the user.

However, this customization is limited. On the shield you can only customize the text and the background color of the shield. You can’t add brand assets on the shield or change the background color to a gradient color. This was probably an intentional restriction to ensure that users are able to recognize the shield every time it pops up.

DeviceActivity (The Scheduler & Monitor)

DeviceActivity allows your app to schedule the time that the restrictions you have set up becomes active on your user’s device. It also monitors user’s device usage and allows you to trigger restrictions when certain thresholds are reached.

DeviceActivity also allows you to generate custom device usage reports using SwiftUI. The usage data is accessed through an extension where developers can choose what usage data is displayed and how it is displayed.

But, if you attempt to extract the usage data to your main app, it returns absolutely nothing. The usage data can only be accessed in the extension and visually displayed using SwiftUI. Apple never shows the developer the usage data of the user.

How the Three Frameworks Work Together

Simply, FamilyControls asks the user for permission and what to control; ManagedSettings sets up the actual restriction; and DeviceActivity controls when that restriction is turned on and off.

Apple’s Screen Time Architecture

Apple ‘s Screen Time Architecture is set up to ensure that a larger percentage of control remains with the user and the OS. Your app may set the limitations but every restriction must be authorized by the user (or guardian of the user). Those rules are only then enforced through the ManagedSettings by the OS, not your app. Because of this, even if your app was force quit or the device restarted. The restrictions you have put in place still remains.

To implement Screen Time, Apple provides different extensions which allow them to handle sensitive processes without exposing user data. These extensions are isolated, heavily sandboxed, have little to no internet access, and have strict execution time. They exists separately, functioning outside your app. The only way they share data with your app or each other is via App Groups. All your extensions need to share the same App Group capability to effectively share data. When issues occur, extensions can be difficult to debug and it can be difficult to track bugs.

The architecture is structured in such a way that developers can participate in the Screen Time experience but the OS remains fully in control. The main app and extensions - working together but fully isolated from each other.

My Research, Expectation and Reality

The Research

As someone with no prior experience with the Screen Time API, I spent the first few weeks studying. I read up articles, skimmed through Apple developer forums, used AI to gather data and googled a lot. At last I felt satisfied having confirmed that using Screen Time API would help me build some of the features I planned to. It is also Apple’s preferred option.

Although, I discovered that there were a few other features that were simply impossible on iOS. For instance, Apple doesn’t allow developers access the names and/or bundle ids of the user’s installed apps. This was disappointing because it was a major product requirement and was already implemented on Android.

So I wrapped up my research knowing that a few features will be put on hold and that certain device control features could only be possible on supervised devices. Supervised devices are devices that have been configured to grant administrators deeper control over device behavior. The issue is, supervised devices are not ideal for commercial use.

The Expectation

From my research, I expected certain features to be straightforward to implement. I began actively thinking of workarounds for other essential features. It was now easier to estimate implementation time for certain features since I had a rough idea of the process. I used AI to try to find loop holes in the implementation plans I had but because the Screen Time API is quite undocumented, many times it made things up. After I noticed this, I started requesting for references to confirm its claims.

From skimming Apple developer Forums, I gathered that there were certain outstanding issues and unpredictable behaviors from some APIs. So I expected it to be an interesting challenge.

The Reality

Building with these APIs exposed me to a lot of things I didn’t find out during my research. I discovered new problems that I didn’t initially account for, I spent hours going round in circles trying to find solutions to certain issues, not knowing that the issue was an intentional restriction. I spent nights debugging with OSLog, surfed Apple developer forums searching for solutions from people with similar problems. I started implementing certain features and had to change how they work halfway due to platform restrictions.

Here are some of the issues I faced during implementation:

  • User’s device usage data is completely unaccessible to the app, even though it can be visually displayed in the app with SwiftUI. It can’t be extracted or even logged. This is because the system runs such extensions in a read-only sandbox. Any attempts to write contents fail silently - no errors. It simply doesn’t work. Attempting to display usage data with Home Screen Widgets on iOS doesn’t work too.
  • Silent push doesn’t work once app is force quit. Since I used silent push to prompt the app to refresh device control rules, the moment the app is force quit there is no way for the app to sync with the backend until the user opens the app again. This meant stale rules and inconsistent behavior. Apparently silent push used to work even when app was force quit but in recent iOS versions that behavior was changed.
  • For Screen time authorized by individuals, it can be toggled off from app settings without any hindrance. This means that the user can simply toggle off screen time for the app, authenticate with face id or pin and all restrictions are automatically lifted. Ideally, one should be able to create a different passcode specifically for Screen Time just like it works for the native Apple Screen Time.
  • Opaque Tokens are what you get when the user selects apps or websites to be restricted through the family activity picker. The tokens are unidentifiable outside the app. It can’t be decrypted. It can’t be generated using bundle ids. This means there is absolutely no way for you to identify the apps/websites selected by your user. Aside from this, sometimes the OS silently changes the tokens and because of this restrictions won’t work, since ManagedSettings can’t identify the token. The user will need to select the apps again from the family activity picker for restrictions to work.
  • On the shield that restricts your users from having access, the secondary button is meant to be configured to request access through your app. The issue is aside from close, the only other possible responses that you can configure are defer and none. None of which can tell your app that the user has just made a request. Ideally one should be able to click on a button on the shield and open your app but Apple has currently confirmed that this action is not supported.

Most of the issues that I experienced point to the fact that user privacy is prioritized over developer experience. Certain features are flat out impossible and there are boundaries to the kind of control your app can exert over the user’s device.

Apple's Choice of Privacy Over Control

Understanding Apple’s choice of privacy over control will help you manage your expectations when attempting to build device control features on iOS platforms. Since Apple owns the platform, you are only going to be able to build what they let you build. This is why it is important to understand the limitations of the platform first and then plan the direction of your product.

This is also why apps that use MDM have a 85% chance of either being removed from Appstore or not even being approved at all. Apple prioritizes user privacy and data safety over anything else and it shows. While this is great for the users, as this action actively protects them from bad actors. It affects developers that are genuinely trying to build control features customized for different use cases or features that address loopholes in Apple’s own native Screen Time.

There are several open issues on the Screen Time API that have been lying unaddressed for a long time now. This may be due to the complexity of the Screen Time API itself, regressions and the burden of building while maintaining the balance between managing user privacy and giving developers access.

Workarounds That Helped

Building in a restrictive environment caused me put think of workarounds to achieve the results I needed. But because it is actually ideal to have these API handle most of these issues out the box, most of these workarounds have their shortcomings.

  • Since I couldn’t open my app from the shield, I opted to trigger a local push notification and then write to the App group store of the pending request. When the user taps on the notification and it opens the app, then the app checks the store for any pending request and then shows the request more time/ request access screen. The drawback for this is that notifications can sometimes be blocked when device is on focus mode.
  • For the opaque tokens that were returned, in areas that I needed to know the selected app, I simply asked the user to name it themselves. This way the privacy still remains between the user and Apple but now at least I had something the user and I could use to identify the app.

Screen Time API vs Apple’s Native Screen Time

The initial assumption I had was that the Screen Time API had the same capabilities with Apple native Screen Time. But that wasn’t the case, as third-party apps only receive a carefully controlled subset of the capabilities available to Apple's own system app.

Apple’s native Screen Time is integrated in the OS, therefore it has direct, privileged access to iOS internals. This gives them unilateral access to everything on the device and this means they have liberty to create any kind of device usage control feature without restrictions.

So why do people want to build their own Screen Time apps? The answer is that while Apple native Screen Time does great on many areas, there are still some loopholes and gaps that many parents and individuals have noticed. Especially in this time when parents and guardians are fighting to protect vulnerable members of their families from all the vices that exist on the internet. That and also most people just want to build customized versions of Screen Time apps to suit specific needs.

But the limitation of the Screen Time API restricts that, giving the Apple native Screen Time the upper hand when one considers functionality and access. Here are some of the things that differentiate Apple native Screen Time from Screen Time API.

Screen Time API vs Apple’s Native Screen Time

You might wonder, what happens when Apple native Screen Time and your Screen Time app using the API are both active on a device?

Your app's ManagedSettingsStore is separate from the one used by Apple's native Screen Time. Each store operates independently and cannot read, modify, or override the other's settings.

For example, if your app blocks YouTube but allows Twitter, while Apple's Screen Time blocks Twitter but allows YouTube, both YouTube and Twitter will end up blocked. This is because restrictions are additive: if any managed settings store applies a restriction to an app, that restriction takes effect.

In practice, a "block" always takes precedence over a "don't block" state. While the stores are isolated from one another, their restrictions are combined by the system when determining what the user can access. As a result, neither your app nor Apple's native Screen Time can remove restrictions imposed by the other.

Conclusion

Building with the Apple Screen Time API was both rewarding and challenging. Getting to experience system restrictions, spending time reading through Apple developers forums in search for answers and understanding the design philosophy behind Apple Screen Time API was an interesting experience.

I understood that the best way to build is to build features within the constraints of the API. Perhaps until things change and the API is upgraded then can anyone build more ambitious features for device usage management. However, trying to build against the current restrictions only leads to frustration.

If you are starting out building with the Screen Time API, I will encourage to you to research and spend sometime understanding the architecture before delving into implementation. However, there are issues you’ll only get to see during implementation and that’s just part of the experience. If you’ll be using AI to research, ensure you validate it’s claims by checking the references and asking for proof. Since Screen Time is not very documented, AI will make things up many times and tell you something is possible when it isn’t.

Most of all, enjoy the journey and go ahead to build applications that help users develop healthier relationships with technology.

For any questions, you can find me on XLinkedIn and Github.

Top comments (0)