Site icon Mobile App Development Services

Parental Control – ScreenTime API iOS

Introduction:

Recently, Apple released the ScreenTime API for iOS. Although the ScreenTime feature has been there since the release of iOS 13, from iOS 15, Apple has introduced ScreenTime API for developers to allow them to develop apps for their user base with customized UI for an enhanced experience for parental controls. It mostly provides features for parental controls such as allowing parents to add restrictions to apps and websites to their child’s device, enabling parents to set time limits on their child’s usage of the device, and sharing usage of the child’s device with parents.

ScreenTime API comprises 3 frameworks:

  1. Managed Settings
  2. Family Controls
  3. Device Activity

Below are the functionalities provided by each framework.

Managed Settings Framework:

Family Controls Framework

Device Activity Framework

Prerequisites

  1. Apple Family Sharing needs to be enabled by the user and family members’ Apple ID should be added there
  2. Adding apple id as a family member enables screen time monitoring for all iOS devices associated with that Apple ID.
  3. Child’s Apple ID can be created by a parent or an existing ID with an age below 18 can be added.

Now let’s code…

First of all, we need to add a Device Monitor Extension to our target. This acts as a background service on a child’s device for various functionalities.

Go to File > New > Target > Choose Device Activity Monitor Extension.

Give the extension the desired name and click Finish. A new group named as your extension will be added in the project. Create a file named as MyMonitor in this group and write the following code.

import UIKit
import MobileCoreServices
import ManagedSettings
import DeviceActivity

class MyMonitor: DeviceActivityMonitor {
    let store = ManagedSettingsStore()
    override func intervalDidStart(for activity: DeviceActivityName) {
        super.intervalDidStart(for: activity)
        print("interval did start")
        let model = MyModel.shared
        let applications = model.selectionToDiscourage.applicationTokens
        store.shield.applications = applications.isEmpty ? nil : applications
        store.dateAndTime.requireAutomaticDateAndTime = true
    }

    override func intervalDidEnd(for activity: DeviceActivityName) {
        super.intervalDidEnd(for: activity)
        store.shield.applications = nil
        store.dateAndTime.requireAutomaticDateAndTime = false
    }
}

The above code overrides the two methods of Device Activity Monitor which are called on the interval start and end respectively, for the intervals defined in the other parts of code. On interval start, we are restricting user/child’s device from changing their date and time along with applying shield to all those apps restricted by the parent.

Now, in the AppDelegate of the main app, write the following code. Also, don’t forget to import FamilyControls framework in AppDelegate.


class AppDelegate: NSObject, UIApplicationDelegate {

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
        AuthorizationCenter.shared.requestAuthorization { result in
            switch result {
            case .success:
                print("Success")
            case .failure(let error):
                print("error for screentime is \(error)")
            }
        }

        _ = AuthorizationCenter.shared.$authorizationStatus
            .sink() {_ in
            switch AuthorizationCenter.shared.authorizationStatus {
            case .notDetermined:
                print("not determined")
            case .denied:
                print("denied")
            case .approved:
                print("approved")
            @unknown default:
                break
            }
        }
        return true
    }
}

The above code will show the below alert to the user for the first time and will require a parent to authenticate on the child’s device.

Authorization alert
Authentication required from parent/guardian

After parent successfully authenticates the child, the next time alert won’t show up and the child cannot delete the app without the parent/guardian’s approval just like as above.

Now create a new Swift file MyModel and write the following code.

import Foundation
import FamilyControls
import DeviceActivity
import ManagedSettings

class MyModel: ObservableObject {
    static let shared = MyModel()
    let store = ManagedSettingsStore()

    private init() {}

    var selectionToDiscourage = FamilyActivitySelection() {
        willSet {
            print ("got here \(newValue)")
            let applications = newValue.applicationTokens
            let categories = newValue.categoryTokens
            let webCategories = newValue.webDomainTokens
            store.shield.applications = applications.isEmpty ? nil : applications
            store.shield.applicationCategories = ShieldSettings.ActivityCategoryPolicy.specific(categories, except: Set())
            store.shield.webDomains = webCategories
        }
    }

    func initiateMonitoring() {
        let schedule = DeviceActivitySchedule(intervalStart: DateComponents(hour: 0, minute: 0), intervalEnd: DateComponents(hour: 23, minute: 59), repeats: true, warningTime: nil)

        let center = DeviceActivityCenter()
        do {
            try center.startMonitoring(.daily, during: schedule)
        }
        catch {
            print ("Could not start monitoring \(error)")
        }

        store.dateAndTime.requireAutomaticDateAndTime = true
        store.account.lockAccounts = true
        store.passcode.lockPasscode = true
        store.siri.denySiri = true
        store.appStore.denyInAppPurchases = true
        store.appStore.maximumRating = 200
        store.appStore.requirePasswordForPurchases = true
        store.media.denyExplicitContent = true
        store.gameCenter.denyMultiplayerGaming = true
        store.media.denyMusicService = false
    }
}

extension DeviceActivityName {
    static let daily = Self("daily")
}

FamilyActivitySelection is a picker provided by the FamilyControls framework which displays all the apps, categories, and websites on a child’s device and allows parents to restrict those apps.

FamilyActivitySelection picker

Above code has the method initiateMonitoring in which we are creating a schedule for 24 hours named as daily for which the Device activity monitor extension will observe. Along with that, we are setting some additional restrictions for the child such as child cannot change date and time, cannot change apple id, passcode, use Siri, download apps above certain rating and much more.

Finally, a view is created in the below code snapshot to display FamilyActivitySelection picker on a button click and start monitoring on child’s device after which all the additional restrictions are applied.

import SwiftUI
import FamilyControls

struct ContentView: View {
    @StateObject var model = MyModel.shared
    @State var isPresented = false
    
    var body: some View {
        Button("Select Apps to Discourage") {
            isPresented = true
        }
        .familyActivityPicker(isPresented: $isPresented, selection: $model.selectionToDiscourage)
        Button("Start Monitoring") {
            model.initiateMonitoring()
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

When a child launches a restricted website or app, the following screen appears which is also customizable in a limited scope. We can only change the logo, title and message of the following screen which we haven’t done in this code. Also, a restriction sign appears on the app icon of the restricted app.

Screen when launching a restricted app.

Issue Found

Although ScreenTime API provides a package to develop a parental control app there’s a lot of immaturity in the API itself. Implementing the above code should have followed the specific behavior of the app flow mentioned by Apple in WWDC21 while the following were the issues faced.

Should be App Flow:

Issues faced:

What’s Next

Recently Apple has introduced some new features in ScreenTime API all 3 frameworks in WWDC22 but I haven’t explored them yet. These new features are available to explore for iOS 16 and above. Also, this tutorial does not have restriction screen customization which can also be explored.