Prevent access to the Screen Time API without guardian approval and provide opaque tokens that represent apps and websites.

All subtopics
Posts under Family Controls topic

Post

Replies

Boosts

Views

Activity

Family Controls (Distribution) was granted to main bundle ID, but not to the extensions
I've successfully obtained Distribution entitlements for Family Controls. However, this seems to only apply to the main target/identifier and not the extensions, like DeviceActivityMonitor, ShieldConfigurationDataSource, or ShieldActionExtension. Did I perhaps fill out the form with the wrong bundle ID? If I go to "Certificates, Identifiers & Profiles", my main identifier for the app has the Distribution entitlement. But the extensions and the wildcard don't. This means that trying to create an archive results in the following two errors, each repeated twice: Provisioning profile failed qualification (Profile doesn't support Family Controls (Development)) Provisioning profile failed qualification (Profile doesn't include the com.apple.developer.family-controls entitlement) Note that my entitlement files are set up correctly. Do I need to fill out the form with a wildcard instead? Or am I doing something wrong? Thank you.
3
0
714
Feb ’25
DeviceActivityMonitor.intervalDidEnd never getting called
I'm trying to build an app with a DeviceActivityMonitor extension that executes some code after 15 minutes. I can confirm that the extension is set up correctly and that intervalDidStart is executed, but for some reason the intervalDidEnd method never gets called. What I'm doing in both is just registering a local notification. class DeviceActivityMonitorExtension: DeviceActivityMonitor { let store = ManagedSettingsStore() override func intervalDidStart(for activity: DeviceActivityName) { createPushNotification( title: "Session activated!", body: "" ) super.intervalDidStart(for: activity) } override func intervalDidEnd(for activity: DeviceActivityName) { createPushNotification( title: "Session ended", body: "" ) super.intervalDidEnd(for: activity) } private func createPushNotification(title: String, body: String) { let content = UNMutableNotificationContent() content.title = title content.body = body // Configure the recurring date. var dateComponents = Calendar.current.dateComponents([.era, .year, .month, .day, .hour, .minute, .second], from: Date().addingTimeInterval(1.0)) dateComponents.calendar = Calendar.current dateComponents.timeZone = TimeZone.current // Create the trigger as a repeating event. let trigger = UNCalendarNotificationTrigger(dateMatching: dateComponents, repeats: false) let uuidString = UUID().uuidString let request = UNNotificationRequest(identifier: uuidString, content: content, trigger: trigger) // Schedule the request with the system. let notificationCenter = UNUserNotificationCenter.current() notificationCenter.add(request) } } And this is the method that is starting the monitoring session: @objc public static func startSession() -> String? { // Calculate start and end times let center = DeviceActivityCenter() let minutes = 15 let startDate = Date().addingTimeInterval(1) guard let endDate = Calendar.current.date(byAdding: .minute, value: minutes, to: startDate) else { return "Failed to create end date?" } // Create date components and explicitly set the calendar and timeZone let startComponents = Calendar.current.dateComponents([.era, .year, .month, .day, .hour, .minute, .second], from: startDate) let endComponents = Calendar.current.dateComponents([.era, .year, .month, .day, .hour, .minute, .second], from: endDate) // Create schedule let schedule = DeviceActivitySchedule( intervalStart: startComponents, intervalEnd: endComponents, repeats: false ) print("Now", Date()) print("Start", startDate, startComponents) print("End", endDate, endComponents) print(schedule.nextInterval) do { // Use a consistent activity name for our simple implementation let activity = DeviceActivityName("SimpleSession") try center.startMonitoring(activity, during: schedule) return nil } catch { return "Failed to start monitoring: \(error)" } } I can confirm my dates & date components make sense with the 4 print statements. Here is the output: Now 2025-02-12 04:21:32 +0000 Start 2025-02-12 04:21:33 +0000 era: 1 year: 2025 month: 2 day: 11 hour: 20 minute: 21 second: 33 isLeapMonth: false End 2025-02-12 04:36:33 +0000 era: 1 year: 2025 month: 2 day: 11 hour: 20 minute: 36 second: 33 isLeapMonth: false Optional(2025-02-12 04:21:33 +0000 to 2025-02-12 04:36:33 +0000) I get the Session activated! notification but never get the Session ended notification. Half an hour later, I've tried debugging the DeviceActivityCenter by printing out the activities property and can see that it is still there. When I try to print out the nextInterval property on the schedule object i get from calling center.schedule(for:), it returns nil. I'm running this on an iPhone 8 testing device with developer mode enabled. It has iOS 16.7.10. I'm totally lost as to how to get this to work.
1
0
394
Feb ’25
Device Activity Report only for Selected Apps
I want to display device activity reports for particular selected apps. for getting a daily basis app uses time. Now, what is happening? there are 10 apps selected from the family activity picker but some apps are displayed in the list. I need all 10 apps or more that I will choose from the family activity picker. The bellow code is used for fetching reports. var body: some View { VStack { DeviceActivityReport(context, filter: filter) } } bellow code is used for the filter @State public var filter = DeviceActivityFilter() init(selectedApps: Set<ApplicationToken>, selectedCategories: Set<ActivityCategoryToken>, selectedWebDomains: Set<WebDomainToken>) { self.selectedApps = selectedApps self.selectedCategories = selectedCategories self.selectedWebDomains = selectedWebDomains self.filter = DeviceActivityFilter( segment: .daily( during: Calendar.current.dateInterval( of: .weekOfYear, for: .now )! ), users: .all, devices: .init([.iPhone]), applications: selectedApps, categories: selectedCategories, webDomains: selectedWebDomains ) } You can see we selected 3 apps from family activity picker but we getting 2 apps from DeviceActivityReport extension following code is for device activity report extension let context: DeviceActivityReport.Context = .totalActivity // Define the custom configuration and the resulting view for this report. let content: (ActivityReport) -> TotalActivityView func makeConfiguration(representing data: DeviceActivityResults<DeviceActivityData>) async -> ActivityReport { // Reformat the data into a configuration that can be used to create // the report's view. var res = "" var list: [AppDeviceActivity] = [] let totalActivityDuration = await data.flatMap { $0.activitySegments }.reduce(0, { $0 + $1.totalActivityDuration }) for await d in data { res += d.user.appleID!.debugDescription res += d.lastUpdatedDate.description for await a in d.activitySegments{ res += a.totalActivityDuration.formatted() for await c in a.categories { for await ap in c.applications { if let apptoken = ap.application.token { let appName = (ap.application.localizedDisplayName ?? "nil") let bundle = (ap.application.bundleIdentifier ?? "nil") let duration = ap.totalActivityDuration let numberOfPickups = ap.numberOfPickups let app = AppDeviceActivity(appToken: apptoken, id: bundle, displayName: appName, duration: duration, numberOfPickups: numberOfPickups) list.append(app) } } } } } return ActivityReport(totalDuration: totalActivityDuration, apps: list) }
4
0
1k
Feb ’25
DeviceActivityMonitor extension does not call back at the set time
Hello Apple development team, I have developed an App for screen time management, which mainly uses ScreenTimeAPI. Users can set certain Apps to be disabled during a certain period of time. After the App is released, users often report that the settings do not take effect as expected. I have seen many developers on the forum reporting that the DeviceActivityMonitor extension sometimes does not trigger callbacks. Based on this background, I have the following questions: Is it a known problem that the DeviceActivityMonitor extension sometimes does not trigger callbacks? If so, are there any means to avoid or reduce the probability of occurrence? In addition to being killed by the system when the running memory exceeds (I just called some ScreenTimeAPI and accessed UserDefaults in the extension, which should not exceed the running memory), under what other circumstances will the DeviceActivityMonitor extension be killed by the system? Will it automatically recover after being killed? Will some callbacks be called when killing? Does ManagedSettingsStore have a life cycle? How do you avoid conflicts when configuring the underlying operating mechanism of multiple stores? This is a random problem. I have never encountered it during development and debugging, but users often report it. thanks
1
0
534
Feb ’25
Any workaround for expanding a large category in FamilyActivityPicker?
I’m developing a self-management app using Family Controls, but I’ve encountered a FamilyActivityPciker's crash due to an XPC(or UIRemoteView) issue when there are too many tokens(maybe 200+ items) in a category. This makes bad UX, so I’m looking for a workaround. (I guess that the crash reason is cross process memory limitations, such as App Extension 50MB memory limitation.) A lot of web domains contribute to increase the number of tokens, However, even after clearing Safari’s browsing history, the tokens displayed in the FamilyActivityPicker remains unchanged. Is there any workaround that a 3rd party developer can implement to address this issue? prevent FamilyActivityPicker crashes or reduce the number of web domain tokens? For example, if there’s a way to reset the web domain tokens shown in FamilyActivityPicker from the Settings app, I could offer a help to users. Does anybody have ideas? Expanding SNS Category (29 items) It succeeded. Expanding Productivity & Finance (214 items) It failed. The screen froze, then appears blank. When the number of items is around 100, the crash rate is 50%, but when the items are over 200, the crash rate is 100%. Search Bar Problem The search bar also has same problem. If the number of search results are small, it works good without any blank, but if there are a lot of search results (200+), the XCP crashes and the screen appears blank. Code to Reproduce import SwiftUI import FamilyControls struct ContentView: View { @State private var selection = FamilyActivitySelection() @State private var isPickerPresented: Bool = false var body: some View { VStack { Button("Open Picker") { isPickerPresented = true } } .familyActivityPicker(isPresented: $isPickerPresented, selection: $selection) } } Steps to Reproduce Prepare a category that has 200+ items Try to open the category in the picker The screen will freeze, then appears blank. Errors in Console [u EDD60B83-5D2A-5446-B2C7-57D47C937916:m (null)] [com.apple.FamilyControls.ActivityPickerExtension(1204)] Connection to plugin interrupted while in use. AX Lookup problem - errorCode:1100 error:Permission denied portName:'com.apple.iphone.axserver' PID:2164 ( 0 AXRuntime 0x00000001d46c5f08 _AXGetPortFromCache + 796 1 AXRuntime 0x00000001d46ca23c AXUIElementPerformFencedActionWithValue + 700 2 UIKit 0x0000000256b75cec C01ACC79-A5BA-3017-91BD-A03759576BBF + 1527020 3 libdispatch.dylib 0x000000010546ca30 _dispatch_call_block_and_release + 32 4 libdispatch.dylib 0x000000010546e71c _dispatch_client_callout + 20 5 libdispatch.dylib 0x00000001054765e8 _dispatch_lane_serial_drain + 828 6 libdispatch.dylib 0x0000000105477360 _dispatch_lane_invoke + 408 7 libdispatch.dylib 0x00000001054845f0 _dispatch_root_queue_drain_deferred_wlh + 328 8 libdispatch.dylib 0x0000000105483c00 _dispatch_workloop_worker_thread + 580 9 libsystem_pthread.dylib 0x0000000224f77c7c _pthread_wqthread + 288 10 libsystem_pthread.dylib 0x0000000224f74488 start_wqthread + 8 ) Error acquiring assertion: <Error Domain=RBSAssertionErrorDomain Code=2 "Specified target process does not exist" UserInfo={NSLocalizedFailureReason=Specified target process does not exist}>
7
5
2.3k
Feb ’25
ManagedSettingStore limits and groups
So what's the point of being able to block unto 50 apps per ManagedSettingStore via store.application.blockedApplications (which works fine) until removing the blocked apps or clearing the store. Where the following occurs if you have a social networking group with more than 9 apps only 9 apps will go back into the group and all the others will go onto the springboard all jumbled if you end up with an empty group then tap into the group, it is removed then during the reset all apps are placed back on to the springboard
0
0
341
Jan ’25