ios – Scheduling not starting using the ScreenTimeAPI in swiftui


Scheduling doesn’t start and end automatically using the screentime API. The only way I have got it to work is calling MyModel.shared.setAppRestrictions() manually and then by calling MyModel.shared.stopAppRestrictions() manually to stop it.

I have tried calling setAppRestrictions from the DeviceActivityCenter too but that didn’t work. When I call setScedule() from AppDelegate then it blocks the app forever and never unblocks them on time. I am very lost.

Here are my files for both MyModel and MySchedule


import FamilyControls
import Foundation
import ManagedSettings

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

    @Published var selectionToDiscourage: FamilyActivitySelection
    private let decoder = PropertyListDecoder()

    init() {
        selectionToDiscourage = FamilyActivitySelection()
        selectionToDiscourage = loadSelection() ?? FamilyActivitySelection()
    }

    func setShieldRestrictions() {
        // Pull the selection out of the app's model and configure the application shield restriction accordingly
        let applications = MyModel.shared.selectionToDiscourage

        store.shield.applications = applications.applicationTokens.isEmpty ? nil : applications.applicationTokens
        store.shield.applicationCategories = applications.categoryTokens.isEmpty
            ? nil
            : ShieldSettings.ActivityCategoryPolicy.specific(applications.categoryTokens)
        //store.application.denyAppRemoval = true
        //store.dateAndTime.requireAutomaticDateAndTime = true
    }

    func stopAppRestrictions() {
        // lock application
        store.shield.applications = nil
        store.shield.applicationCategories = nil

        // more rules
        store.media.denyExplicitContent = false

        // prevent app removal
        store.application.denyAppRemoval = false
        print("deny app removal: ", store.application.denyAppRemoval ?? false)

        // prevent set date time
        store.dateAndTime.requireAutomaticDateAndTime = false
    }
    

    func loadSelection() -> FamilyActivitySelection? {
        guard let data = UserDefaults.standard.data(forKey: "appModel") else {
            return nil
        }

        return try? decoder.decode(FamilyActivitySelection.self, from: data)
    }
}

import DeviceActivity
import Foundation
import SwiftUI

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

class MonitoringStatus: ObservableObject {
    @Published var isMonitoring: Bool = false
}

// The Device Activity schedule represents the time bounds in which my extension will monitor for activity

enum MySchedule {
    public static func unsetScedule() {
        let center = DeviceActivityCenter()
        if center.activities.isEmpty {
            return
        }

        center.stopMonitoring()
    }

    public static func setSchedule() {
        @AppStorage("fromTime") var fromTime = ""
        @AppStorage("toTime") var toTime = ""

        let selectedDays = getSelectedDays()

        for day in selectedDays {
            let weekdayNumber = dayToWeekdayNumber(day)
            createSchedule(weekdayNumber: weekdayNumber, fromTime: fromTime, toTime: toTime)
        }
    }

    private static func getSelectedDays() -> [Day] {
        guard let dayStrings = UserDefaults.standard.object(forKey: "selectedDays") as? [String] else {
            return []
        }

        return dayStrings.compactMap { Day(rawValue: $0) }
    }

    private static func createSchedule(weekdayNumber: Int, fromTime: String, toTime: String) {
        let startTimeComponents = convertStringToDateComponents(fromTime, weekday: weekdayNumber)
        let endTimeComponents = convertStringToDateComponents(toTime, weekday: weekdayNumber)

        let schedule = DeviceActivitySchedule(
            intervalStart: startTimeComponents,
            intervalEnd: endTimeComponents,
            repeats: true // This should probably be true for a weekly repeating schedule
        )

        let center = DeviceActivityCenter()
        do {
            let activityName = DeviceActivityName("daily_\(weekdayNumber)")
            print("Mointor \(weekdayNumber) with activity name \(activityName)...")
            try center.startMonitoring(activityName, during: schedule)
        } catch {
            print("Error monitoring schedule: ", error)
        }
    }
}

private func convertStringToDateComponents(_ timeString: String, weekday: Int) -> DateComponents {
    var components = convertStringToDateComponents(timeString)
    components.weekday = weekday
    return components
}

private func convertStringToDateComponents(_ timeString: String) -> DateComponents {
    let dateFormatter = DateFormatter()
    dateFormatter.dateFormat = "HH:mm"

    if let date = dateFormatter.date(from: timeString) {
        let calendar = Calendar.current
        let hour = calendar.component(.hour, from: date)
        let minute = calendar.component(.minute, from: date)
        return DateComponents(hour: hour, minute: minute)
    } else {
        // Handle invalid string format or return a default value
        return DateComponents()
    }
}

private func dayToWeekdayNumber(_ day: Day) -> Int {
    // Adjust based on your calendar's first weekday (e.g., Sunday = 1, Monday = 2, etc.)
    switch day {
    case .Sunday: return 1
    case .Monday: return 2
    case .Tuesday: return 3
    case .Wednesday: return 4
    case .Thursday: return 5
    case .Friday: return 6
    case .Saturday: return 7
    }
}

Latest articles

spot_imgspot_img

Related articles

Leave a reply

Please enter your comment!
Please enter your name here

spot_imgspot_img