Screen Time API is a proposed cross platform API to allow third-party developers to provide apps that can monitor and control the time spent using the device. It aims to provide a generic API that can be used for a wide range of use cases, from personal health to remote parental controls to social media monitoring. It also aims to do this in a way that is respectful of the device owners privacy, by not providing more information than is nessessary and using the platforms permissions system to access data. This document shows how the API would look for iOS, MacOS and tvOS.
In its most minimal form, the API only gives access to App and Device usage data, but no App data is exposed. So the Screen Time API app knows that you used Safari for 10 mins at 11am, but has no idea what you did in Safari. With more permissions, the Screen Time API app is able to stop you from using Safari at this point.
The Screen Time API makes available existing networking APIs for monitoring network activity on a device. These are powerful APIs for monitoring all network connections from the device. These could be used by apps for basic content filtering as well as for more advanced features such as monitoring and blocking social networking apps. This would also allow privacy apps to monitor and block trackers in all the apps on a device. These APIs work for all web browsers and apps.
Technically, the API provides events to an app, (e.g. that an app is being opened or a notification is about to be shown) and allows that app to allow or block this action. That app can also present its own view to interupt what the user is doing in another app.
The diagram below provides an overview of how an app would use the API, showing the interaction between the app and the system.
class STKManager {
static default: STKManager
}
This would be the main class for interacting with Screen Time API on the device, accessed as a static singleton from the app or extension.
func register(eventTypes: [.openApp, .closeApp])
Register this app as the/a Screen time manager on the device. This would trigger the user to setup a PIN code, for parental controls, and enable all the apis/extension.
The app can no longer be deleted, and this permission cannot be changed without providing the parental control PIN.
func deregister()
Stop the extension from receving events, also the app can be deleted normally.
func authorizationStatus() -> STKAuthorizationStatus
Get the apps authorization status, similar to CLLocationManager
, there are two levels of access, to allow the app to only access tracking information, or to allow the app to control the device.
The functions to present app UI at anytime, and prevent apps from loading are not available when the user chooses tracking only.
enum STKAuthorizationStatus {
case notDetermined
case restricted
case denied
case authorizedAccess
case authorizedControl
}
func apps() -> [App]
Get a list of apps that are currently installed on the device.
struct App {
name: String
itunesStoreId: String
bundleIdentifier: String
version: String
icon: UIImage,
rating: Int
}
func isChild() -> Bool
Find out if the apple id on the device is a child account.
var restrictions: Restrictions
Property for managing restrictions on the device, just like MDM provided or in Restrictions settings on the device.
struct Restrictions {
allowAppInstallation: Bool
allowCamera: Bool
allowChat: Bool
allowCloudDocumentSync: Bool
allowFindMyDevice: Bool
allowFindMyFriends: Bool
allowGameCenter: Bool
allowHome: Bool
allowNews: Bool
allowPairedWatch: Bool
allowPodcasts: Bool
allowSafari: Bool
allowUIAppInstallation: Bool
allowVideoConferencing: Bool
allowiTunes: Bool
maximumMovieRatingForAgeGate: Double
maximumTVShowRating: Double
maximumTVShowRatingForAgeGate: Double
maximumMovieRating: Double
}
func queryEvents(from: Date, to: Date, eventTypes: [.openApp, .closeApp]) -> [Event]
Allows access to the history of events.
func sendMessage(_ messageData: Data,
responseHandler: ((Data?) -> Void)? = nil) throws
Send a message to the Screen Time extension. This can be used for comunication between the host app and the extension.
var delegate: STKManagerDelegate?
Assign a delegate to the manager.
protocol STKManagerDelegate {
}
optional func screenTimeManager(_ manager: STKManager,
didChangeAuthorization status: STKAuthorizationStatus)
Get updates on the STKAuthorizationStatus
, will be called if the user disables the screen time app. The app can be launched in the background to enable handling of this event.
The next part would be an app extension. The main class of the extension should extend from this class, and override the methods needed.
class ScreenTimeEventsHandler {
}
func before(event: Event, response: (EventResponse) -> Void)
This would be the extension function to implement, receive event and provide a response, to allow or block the event from proceeding.
E.g. with notifications, the function is called first, and if the extension returns .block
then iOS will not show the notification.
The list of events could be expanded futher to include other OS events that are relevent. E.g. for desktop platforms events for file downloads or user login would be for interest.
struct Event {
eventType: EventType
identifier: Int
at: Date
}
enum EventType {
case openApp(App)
case closeApp(App)
case installApp(App)
case uninstallApp(App)
case lockScreen
case unlockScreen
case devicePickUp
case notification(App, userInfo: [AnyHashable : Any])
case makePhoneCall(Contact)
case receivePhoneCall(Contact)
case sendMessage(Contact, Message)
case receiveMessage(Contact, Message)
}
enum EventResponse {
case allow
case block
}
func after(event: Event)
Called after the event has finished happening.
func present(_ viewControllerToPresent: UIViewController,
animated flag: Bool,
completion: (() -> Void)? = nil)
Similar to in UIViewController
to allow the extension to present a view controller at any time.
The view controller would yield to the system via the extensionContext
.
This can be called during the before
or after
events, or in response to some other app specific logic, e.g. a time limit has been reached.
func handleAppMessage(_ messageData: Data,
completionHandler: ((Data?) -> Void)? = nil)
Handle messages sent by the extensions containing app. Similar to NETunnelProvider
.
A new UIBackgroundMode is added, screentime
, to allow an app to always receive background location updates.
The app will still ask for location permissions in the normal way, but if the app gets 'always' permission, even if the user quits the app it will be relaunched. This allows a parental control app to reliably receive location updates when the child might try to prevent it from doing so.
An app with this mode will also always receive remote notifications in the background, again even if the user has quit the app. This means a parental control app will be able to use push notifications to delivery configuration changes to the extension.
Currently Content Filter Providers are only supported on supervised iOS devices. This is changed to allow Screen Time API apps to create content filters. More data is exposed to content filter apps, in a way that Apple has designed and already allows schools and businesses to use. This level allows complete web data. This API is more powerful that the currently available Safari Content Blocker because it allows apps to filter for all web browsers and apps and make intelligent decisions about content not just provide basic block lists.
The extension can be enabled using NEVPNManager
and iOS should ask for permissions from the user to enable it. Similar to enabling a screen time app, the parental control PIN code should be provided/created in order to enable it.
A function should be added to NEVPNManager
to allow the app to get its current authorization status.
func authorizationStatus() -> NEAuthorizationStatus
Similarly, DNS Proxy Providers are only supported on supervised iOS devices. This is changed to allow Screen Time API apps to create dns proxy providers in exactly the same way as content filter providers.
DNS Proxy Providers are a less intrusive way to monitor and block network activity, as they dont get access to the content of networking, just the domain names being accessed. This would be appriate for apps that dont need full access to the network.