logo hsb.horse
← Back to blog index

Blog

A Design Guide to Building an iOS Self-Control App with the Screen Time API

From the NEDNSProxyProvider dead end to a FamilyControls + ManagedSettings design, the two Shield Extensions, App Group unlock handoff, and Personal Team limitations. This article summarizes the full picture of building an iOS blocking app with the Screen Time API.

Published:

If you try to build a self-control app for blocking websites while being new to iOS development, you quickly run into a series of “this is not what I expected” moments. I started with NEDNSProxyProvider because I was aiming for DNS-level blocking, then learned about extensions, hit signing limitations, and eventually got to the actual way the Screen Time API is meant to be used.

This article is an index that links together five separate posts from that process. I hope it helps anyone with little iOS experience who is stuck on the same problem.


1. Do not take the wrong path at the start

When you look for a way to block websites on iOS, NEDNSProxyProvider appears to be exactly what you want. The name fits, the use case sounds right, but it is not for App Store apps. It is intended for supervised devices managed through MDM.

Do not choose NEDNSProxyProvider when building website blocking on iOS

Read this before you decide whether to abandon the DNS-blocking idea and move to the Screen Time API.


2. The basic Screen Time API design

The right combination is FamilyControls + ManagedSettings. You request authorization with AuthorizationCenter, let the user choose what to block with FamilyActivityPicker, and write rules into ManagedSettingsStore.

Designing self-control blocking on iOS with FamilyControls + ManagedSettings

Trying to manage blocked targets as free-text URLs will lead you into a dead end. This article also explains why the token-based design centered on FamilyActivitySelection is the real premise.


3. You need two Shield Extensions

To customize the shield screen shown after ManagedSettings applies rules, you need two extensions. If you assume adding one target in Xcode is enough, this is where you get stuck.

An iOS Shield UI Needs Two Extensions, Not One

It organizes the Extension Point Identifier values, principal classes, and Info.plist settings for both the Shield Action Extension (ShieldActionDelegate) and the Shield Configuration Extension (ShieldConfigurationDataSource).


4. Unlock handoff from the shield to the app

Apple does not provide a route that lets the shield screen directly launch the main app and run an unlock flow. ShieldActionDelegate can return only .close or .defer.

Implementing unlock handoff from a Shield Extension to the main app via App Group

That article explains the handoff pattern where the extension writes an “unlock request” into shared UserDefaults inside an App Group, and the app reads it when the user opens the app. It also covers why this limitation exists and how to make the UX acceptable within that constraint.


5. You need a paid developer account for device testing

The Family Controls (Development) entitlement is not available on a Personal Team using a free Apple ID. Real device testing requires joining the Apple Developer Program.

Family Controls cannot be tested on a real device with a Personal Team

That article organizes what you can and cannot do on the simulator, how this relates to other entitlements such as In-App Purchase, and when it makes sense to pay for the program.


Summary as a development sequence

If you are building this kind of app without prior iOS experience, the implementation order becomes much cleaner after reading those five posts.

First, give up on the NEDNSProxyProvider idea. Next, settle the basic FamilyControls + ManagedSettings design and build the UI flow with AuthorizationCenter and FamilyActivityPicker. Then add the two Shield Extensions and configure Info.plist correctly. After that, implement the App Group-based unlock handoff. Finally, join the Apple Developer Program and verify everything on a real device.

In this order, you minimize the chance of rebuilding the design later. When you are new to iOS, choosing the wrong API at the beginning tends to poison everything that comes after it, so confirming the direction first is what saves the most time.