I'm a new Swift Developer so I apologise if this is a basic question but I couldn't find the answer anywhere.
I created a basic app to shield selected apps using FamilyControls. Note, this is for an individual phone and not a use case of parents blocking apps on a childs iPhone.
In the iOS Target, I have a Restrictions Manager class which loads apps that user wants restricted and shields them. It can remove restrictions as well.
import Foundation
import FamilyControls
import ManagedSettings
//import Combine
private let _RestrictionsManager = RestrictionsManager()
class RestrictionsManager: ObservableObject {
@Published var activitySelection = FamilyActivitySelection()
let store = ManagedSettingsStore()
//private var cancellables = Set<AnyCancellable>()
private let encoder = PropertyListEncoder()
private let decoder = PropertyListDecoder()
init() {
loadSelection()
}
class var shared: RestrictionsManager {
return _RestrictionsManager
}
func saveSelection(selection: FamilyActivitySelection) {
let defaults = UserDefaults.standard
do {
let data = try encoder.encode(selection)
defaults.set(data, forKey: UserDefaultsKeys.selectedApplications)
//print("Save Selection / Applications Saved")
store.shield.applications = activitySelection.applicationTokens.isEmpty ? nil : activitySelection.applicationTokens
} catch {
print("Failed to save selection: \(error)")
}
}
func loadSelection() {
let defaults = UserDefaults.standard
guard let data = defaults.data(forKey: UserDefaultsKeys.selectedApplications) else { return }
do {
activitySelection = try decoder.decode(FamilyActivitySelection.self, from: data)
//print("Load Selection / Applications Loaded")
} catch {
print("Failed to load selection: \(error)")
}
store.shield.applications = activitySelection.applicationTokens.isEmpty ? nil : activitySelection.applicationTokens
}
func removeRestrictions() {
store.shield.applications = nil
}
}
I saw some tutorial and also created this schedule file
import Foundation
import DeviceActivity
extension DeviceActivityName {
static let daily = Self("daily")
}
extension DeviceActivityEvent.Name {
static let blocked = Self("blocked")
}
let schedule = DeviceActivitySchedule(
intervalStart: DateComponents(hour: 17, minute: 21),
intervalEnd: DateComponents(hour: 23, minute: 59),
repeats: true
)
class MySchedule {
static public func setSchedule() {
let events: [DeviceActivityEvent.Name: DeviceActivityEvent] = [
.blocked: DeviceActivityEvent (
applications: RestrictionsManager.shared.activitySelection.applicationTokens,
threshold: DateComponents(second: 10)
)
]
let center = DeviceActivityCenter()
do {
try center.startMonitoring(.daily, during: schedule, events: events)
print("Activity Monitoring Schedule Set")
} catch {
print ("Error monitoring schedule: \(error.localizedDescription)")
}
}
}
In the main app file, I'm setting the schedule
import SwiftUI
import FamilyControls
import ManagedSettings
@main
struct Exercise_MommyApp: App {
@UIApplicationDelegateAdaptor private var appDelegate: AppDelegate
let persistenceController = PersistenceController.shared
@StateObject var restrictionManager = RestrictionsManager.shared
@StateObject var store = ManagedSettingsStore()
var body: some Scene {
WindowGroup {
ContentView()
.environment(\.managedObjectContext, persistenceController.container.viewContext)
.environmentObject(restrictionManager)
.environmentObject(store)
}
}
}
class AppDelegate: NSObject, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
MySchedule.setSchedule()
return true
}
}
Content View to take family controls permission
import SwiftUI
import FamilyControls
struct ContentView: View {
@State private var isPermissionGranted = false
var body: some View {
VStack {
if isPermissionGranted {
AppSelectionView()
} else {
Text("Requesting Screen Time permissions...")
.padding()
.onAppear {
requestScreenTimePermissions()
}
}
}
}
private func requestScreenTimePermissions() {
let ac = AuthorizationCenter.shared
Task {
do {
try await ac.requestAuthorization(for: .individual)
isPermissionGranted = true
} catch {
print("Error requesting Screen Time permissions: \(error)")
// Handle permission error
}
}
}
}
Application Selection View
import SwiftUI
import FamilyControls
import DeviceActivity
struct AppSelectionView: View {
@State private var pickerIsPresented = false
@EnvironmentObject var restrictionManager: RestrictionsManager
var body: some View {
VStack {
Text("Select Apps to Monitor")
.font(.headline)
.padding()
Button("Select Apps") {
pickerIsPresented = true
}
.familyActivityPicker(
isPresented: $pickerIsPresented,
selection: $restrictionManager.activitySelection
)
.padding()
Button("Remove Restrictions") {
restrictionManager.removeRestrictions()
}
Button("Add Restrictions") {
restrictionManager.loadSelection()
}
}
.onChange(of: restrictionManager.activitySelection) {
restrictionManager.saveSelection(selection: restrictionManager.activitySelection)
restrictionManager.loadSelection()
}
}
}
Now the application selection view is working fine in terms of taking permissions on which apps to block, saving it. and the buttons to lock and unlock shields is working fine. The problem is in the DeviceActivityMonitor extenstion. Unable to understand how to get access to the applications list here to apply shields.
import DeviceActivity
import ManagedSettings
import SwiftUI
class DeviceActivityMonitorExtension: DeviceActivityMonitor {
let store = ManagedSettingsStore()
override func intervalDidStart(for activity: DeviceActivityName) {
print("intervalDidStart")
super.intervalDidStart(for: activity)
}
override func intervalDidEnd(for activity: DeviceActivityName) {
print("intervalDidEnd")
super.intervalDidEnd(for: activity)
}
override func eventDidReachThreshold(_ event: DeviceActivityEvent.Name, activity: DeviceActivityName) {
print("eventDidReachThreshold")
super.eventDidReachThreshold(event, activity: activity)
}
}
Sorry for the long question but i've been stuck here for 2 days :/
In the DeviceActivityMonitorExtension, the print statements are being called but I don't know how to access the list of applicationtokens here which the user has selected.