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)
}
Prevent access to the Screen Time API without guardian approval and provide opaque tokens that represent apps and websites.
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
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.
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.
Topic:
App Store Distribution & Marketing
SubTopic:
App Store Connect
Tags:
Entitlements
Family Controls
I'm creating an app which gamifies Screen Time reduction. I'm running into an issue with apples Screen Time setting where the user can disable my apps "Screen Time access" and get around losing the game.
Is there a way to detect when this setting is disabled for my app? I've tried using AuthorizationCenter.shared.authorizationStatus but this didn't do the trick. Does anyone have an ideas?
Is it possible to change the title "Choose Activites" and also remove the search on the FamilyActivityPicker?
I have noticed that when I select the app token of the youtube app to be blocked via a ManagedSettingsStore, the youtube website is blocked as well (which is a good and intended behavior IMO).
But how do I know in the ShieldConfigurationDataSource’s override func configuration(shielding webDomain: WebDomain, in category: ActivityCategory) -> ShieldConfiguration to which ManagedSettingsStore the WebDomain’s token is related?
We use different ManagedSettingsStores for different block purposes, which differentiate in their ShieldConfiguration.
Thanks a lot and have a great day!
Hi there,
I am planning an app that requires use of the Family Controls Entitlement to access data on the user's screen time.
I understand that this has to be requested from Apple before it can be used in production.
I have found the following form to request approval, but it requires an App and bundle ID, which suggests that approval can only be requested after the app has been developed.
https://developer.apple.com/contact/request/family-controls-distribution
I'd like to avoid the situation where I spend a lot of time on developing the app, only to find out that the Family Controls Entitlement will not be granted for my use case.
Is there any way that I can request provisional pre-approval for my app? Perhaps based on an app description and some mockups? Or, at least some idea of whether my particular use case is likely to be approved?
Thanks.
I am developing a parental control app using Apple’s Screen Time API and FamilyControls Framework. My goal is to allow parents to remotely block apps on their child’s device from their own phone. Anyone have any idea how can i do that?
Topic:
App & System Services
SubTopic:
General
Tags:
Family Controls
Device Activity
Managed Settings
I am developing a parental control app using Apple’s Screen Time API and FamilyControls Framework. My goal is to allow parents to remotely block apps on their child’s device from their own phone. Does anyone have any idea how I can achieve that?
Topic:
App & System Services
SubTopic:
General
Tags:
Family Controls
Device Activity
Managed Settings
I'm at my wit's end here with an iOS app I'm developing. I've applied for the Family Controls entitlement, and while my extensions (like Device Monitor) have been accepted, the main target entitlement for my app still hasn't been approved.
Here's the timeline:
Extensions (Device Monitor etc.): Accepted about a month ago. Main App Entitlement: Still pending - it's been over 6 weeks now. I'm looking for:
Anyone who has gone through this process and can share how long it took for their main app entitlement to get approved after the extensions were. Any tips on what might speed up the process or what I might be doing wrong. Experiences with contacting Apple Developer Support regarding this issue.
If you've been through a similar ordeal or have any advice, I'd really appreciate it. Thanks for any help or insight you can offer!
I am able to block apps using FamilyControl and Shield. Unblocking is also simple—just assign nil to store.shield.applications. However, I want to unblock them even when the app is not open.
Use case: Let's say the app allows users to create a session where a particular app is blocked for a specific duration. Once the session starts, the app should remain blocked, and as soon as the session time ends, it should automatically be unblocked.
Please help me with this. Thank you!
We developing an app, It's a Parental control app required to block large number of apps. In child mobile installed more than 200 apps parent has to block and disable these apps but parent cant able to block more than 50 apps. Is there any option is there to block all the 200 apps from child mobile.
Hello everyone,
I’m currently developing an app that uses the Family Controls API, specifically the Screen Time API. However, my current entitlement is limited to development mode, which prevents me from publishing my app on TestFlight.
I have already contacted Apple Developer Support for production access but wanted to reach out to the community as well and I was referenced to FamilyControls API documentation and I couldn't find anything related to my case. Has anyone successfully upgraded their entitlement from development-only to production? Any insights on the process, tips for communicating with Developer Support, or guidance on ensuring full compliance with the Family Controls guidelines would be extremely helpful.
The DeviceActivityReport view does not render immediately when added to the view hierarchy. Instead, it requires repeated navigation to the screen hosting the DeviceActivityReport view for it to appear.
Furthermore, there is no programmatic way to determine whether the view is being rendered for the user, leading to an inconsistent and often poor user experience.
I've created a sample project that demonstrates the issue.
I have a model with a FamilyActivitySelection, currently i'm using a codable struct to store it with UserDefaults, but would prefer strongly to transition to Swift Data
I want to monitor again from the bellow function of DeviceActivityMonitorExtension. I have the function of startMonitoring like this.
override func eventDidReachThreshold(_ event: DeviceActivityEvent.Name, activity: DeviceActivityName) {
super.eventDidReachThreshold(event, activity: activity)
startMonitoring()
}
public func startMonitoring() {
let startTime = DateComponents(hour: 0, minute: 0, second: 0)
let endTime = DateComponents(hour: 23, minute: 59, second: 59)//DateComponents(hour: 11, minute: 0, second: 0)//
let schedule = DeviceActivitySchedule(
intervalStart: startTime,//DateComponents(hour: 0, minute: 0, second: 0),
intervalEnd: endTime,
repeats: true
//warningTime: DateComponents(minute:1)
)
let selection: FamilyActivitySelection = savedSelection() ?? FamilyActivitySelection()
let center = DeviceActivityCenter()
let selections = self.savedSelection() ?? FamilyActivitySelection()
let applications = selections.applicationTokens
let categories = selections.categoryTokens
let webCategories = selections.webDomainTokens
let store = ManagedSettingsStore()
store.shield.applicationCategories = ShieldSettings.ActivityCategoryPolicy.specific(categories, except: Set())
store.shield.applications = applications
store.shield.webDomains = webCategories
let scheduleHard = DeviceActivitySchedule(
intervalStart: startTime,//DateComponents(hour: 0, minute: 0, second: 0),
intervalEnd: endTime,
repeats: true
//warningTime: DateComponents(minute:1)
)
let event = DeviceActivityEvent(
applications: selection.applicationTokens,
categories: selection.categoryTokens,
webDomains: selection.webDomainTokens,
threshold: DateComponents(minute: 0)//timeLimitToUseApp i.e for 15 mins
)
do {
try center.startMonitoring( .weekend,
during: scheduleHard,
events: [
.weekend: event,
]
)
print("ScreenTime Monitoring Started")
} catch let error {
print(error.localizedDescription)
}
}
Please provide us with a solution about starting monitoring from DeviceActivityMonitoringExtension's eventDidReachThreshold function or if there is any other way.
I am developing an app that can help users disable selected apps at a specified time, so that users can get away from their phones and enjoy real life.
Here is my data structure:
extension ActivityModel {
@NSManaged public var id: UUID
@NSManaged public var name: String
@NSManaged public var weeks: Data
@NSManaged public var weekDates: Data
@NSManaged public var appTokens: Data
}
Among them, weeks is of [Bool] type, indicating which weeks from Sunday to Saturday are effective; weekDates is of [[Date,Date]] type, indicating the effective time period; appTokens is of Set type, indicating the selected apps。
At the beginning, I will open a main monitor:
let deviceActivityCenter = DeviceActivityCenter()
do{
try deviceActivityCenter.startMonitoring(
DeviceActivityName(activityModel.id),
during: DeviceActivitySchedule(
intervalStart: DateComponents(hour: 0,minute: 0,second: 0),
intervalEnd: DateComponents(hour: 23,minute: 59,second: 59),
repeats: true
)
)
}catch {
return false
}
Since the time range may be different every day, I will start the sub-monitoring of the day every time the main monitoring starts:
override func intervalDidStart(for activity: DeviceActivityName) {
super.intervalDidStart(for: activity)
if activity.rawValue.hasPrefix("Sub-") {
ActivityModelManager.disableApps(
Tools.getUUIDFromString(activity.rawValue)
)
return
}
let weekIndex = Calendar.current.component(.weekday, from: .now)
let weeks = ActivityModelManager.getWeeks(activity.rawValue)
if weeks[weekIndex] {
let weekDates =
ActivityModelManager.getWeekDates(activity.rawValue)
let deviceActivityCenter = DeviceActivityCenter()
do{
try deviceActivityCenter.startMonitoring(
DeviceActivityName("Sub-" + activityModel.id),
during: DeviceActivitySchedule(
intervalStart: getHourAndMinute(weekDates[weekIndex][0]),
intervalEnd: getHourAndMinute(weekDates[weekIndex][1]),
repeats: false
)
)
}catch {
return
}
}esle {
return
}
}
I will judge whether it is main monitoring or sub monitoring based on the different activity names.
When the sub-monitor starts, I will get the bound application and then disable it:
static func disableApps(_ id : UUID){
let appTokens = ActivityModelManager.getLimitAppById(id)
let name = ManagedSettingsStore.Name(id.uuidString)
let store = ManagedSettingsStore(named: name)
store.shield.applications = appTokens
return
}
When the child monitoring is finished, I resume the application:
static func enableApps(_ id : UUID){
let name = ManagedSettingsStore.Name(id.uuidString)
let store = ManagedSettingsStore(named: name)
store.shield.applications = []
}
The above is my code logic.
When using DeviceActivityMonitorExtension, I found the following problems:
intervalDidStart may be called multiple times, resulting in several sub-monitors being started.
After a period of time, the monitoring is turned off.
The static methods enableApps and disableApps are sometimes not called
Topic:
App & System Services
SubTopic:
General
Tags:
Family Controls
Device Activity
Screen Time
Entitlements
After reading Apple documentation (FamilyControls, DeviceActivity, ManagedSettings, ManagedSettingsUI, ScreenTime) and testing the API, I do not find a way to get the child's device apps on the parent device in order to block them or disable them for a certain time.
Is there a way of doing it?
Or can it only be done locally on the child device?
Topic:
App & System Services
SubTopic:
General
Tags:
Family Controls
Device Activity
Managed Settings
Screen Time
Questions
I am developing a social screen time application that enables users to create “sprints” and set sprint goals—essentially time limits on usage for selected applications. For this functionality, users select the apps they wish to manage using the FamilyActivitySelection interface (from the FamilyControls framework).
However, our backend needs to distinguish each application uniquely (for example, via the app’s bundle identifier) in order to correctly map and enforce user-defined sprint goals. Unfortunately, we are encountering an issue where retrieving the bundle identifier directly from the FamilyActivitySelection is returning nil. As a result, we are unable to globally identify the selected apps.
Could you please advise if there is an alternative method or property available in the FamilyControls API that would allow us to uniquely identify the apps? Alternatively, is there another approach recommended by Apple for obtaining a global identifier for applications selected via FamilyActivitySelection?
Thank you for your time and assistance. I look forward to your guidance on how to resolve this issue.
Code
The following is the print statement I used to check if bundleIdentifier is nil after I stored user's selections to the variable selection using familyActivityPicker:
for app in selection!.applications {
let bundleId = app.bundleIdentifier ?? "Unknown Bundle ID"
let token = app.token
let localizedDisplayName = app.localizedDisplayName ?? "Unknown Localized Display Name"
print("Selected app bundle identifier: \(bundleId)")
print("localizedDisplayName: \(localizedDisplayName)")
}
Console log result I received from the print statement above:
Selected app bundle identifier: Unknown Bundle ID
localizedDisplayName: Unknown Localized Display Name
Topic:
Developer Tools & Services
SubTopic:
Xcode
Tags:
Family Controls
Managed Settings
Screen Time
I requested permission to use the Family Controls entitlement two weeks ago, and I have not received a response or status update. I have been to that page where it says "Thank you! We'll get back to you soon!" so many times.