Can ManagedSettingsStore and DeviceActivityCenter be used from a background thread, or do I need to access them from the main thread/queue only?
Device Activity
RSS for tagMonitor web and app usage through custom time windows and events.
Posts under Device Activity tag
82 Posts
Sort by:
Post
Replies
Boosts
Views
Activity
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)
}
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)
}
I know it said that the device activity report extension data cannot be extract but what about importing data to the report ?
⬇️ ANYONE ON APPLE'S SCREEN TIME TEAM, PLEASE READ THIS ⬇️
Let's summarize the situation.
3rd-party apps with screen time access can be disabled by going to Settings > Screen Time > Apps with Screen Time Access. That's fine.
Now, if I want to make it harder to remove my restrictions, I can ask a friend to enter a Screen Time Passcode for me. Great idea!
The problem is my Screen Time Passcode isn't requested when disabling permissions for a third-party app. It's required for modifying any other Screen Time setting EXCEPT permissions for 3rd party apps.
This is frustrating. The Screen Time passcode is a great feature. Making it compatible with permissions granted through the Family Controls framework is our NUMBER ONE REQUEST from tens of thousands of users.
This feature has been requested for a long time (iOS 16, iOS 17, …):
https://forums.developer.apple.com/forums/thread/714651
https://forums.developer.apple.com/forums/thread/727291
https://discussions.apple.com/thread/255421819
FB13548526
If you're a developer working on Screen Time, share your feedback below or file one using Feedback Assistant.
It is very disappointing to see it wasn't implemented for iOS 18. I can't believe this would require tremendous work from the Screen Time team to make it happen, but it would be a significant improvement for the Family Controls Framework and a ray of sunshine for all the developers who have worked really hard to deliver high-quality apps using the Screen Time API.
Could an Apple engineer or a Screen Time team member give us any updates? Implementing this before the public release of iOS 18 would make A LOT of developers happy.
Some of our users encounter an issue after updating their iPhone/iPad to iOS 17.5.1.
The tokens passed in the Shield Configuration extension don't match the tokens they selected in my app using the FamilyPicker before updating to iOS 17.5.1. It seems the tokens changed for no reason. My app can't match the token from the ShieldConfigurationDataSource to any tokens stored on my end, causing my shield screens to turn blank. The same applies to tokens in the Device Activity Report extension.
The only workaround I've found is to tell affected users to unselect and reselect apps and websites to block in my app. This gets them new tokens from the FamilyActivityPicker, which solves the issue. However, for some users, the bug reoccurs a few days later. Tokens seem to change again, causing the same issue in the Shield Configuration extension.
I am not able to reproduce the issue on my test devices so I have no sysdiagnose to attach. However, this issue is affecting other screen time apps:
https://developer.apple.com/forums/thread/732845
https://forums.developer.apple.com/forums/thread/756440
FB14082790
FB14111223
A change in iOS 17.5.1 must have triggered this behaviour. Could an Apple engineer give us any updates on this?
Since iOS 18 Seed 2, I've noticed an issue. When calling startMonitoring(_:during:events:) with an already monitored activity, intervalDidStart in the Device Activity Monitor extension isn't triggered as it should be.
I have to manually call stopMonitoring(_:) BEFORE restarting the activity for intervalDidStart to be called. This is 100% reproducible.
This is different from how it worked before iOS 18 Seed 2 and contradicts the official documentation, which says, “If the app already monitored the activity, this method overwrites the previous schedule and events.” IMO, this suggests we shouldn't have to stop the activity manually; the startMonitoring(_:during:events:) method should handle it automatically.
Is this a mistake or intended behavior?
If intended:
Could you give us the reason?
The documentation should be updated to reflect this change.
I've already filed a feedback about this issue (FB14110789).
Hello,
I am working on an app that schedules a device activity monitor from the screen time API.
I noticed that sometimes scheduling an activity monitor won’t work and instead I see this log:
Canceling request to […].DeviceActivityMonitorExtension because it exceeded its allowed time.
What does this mean? What exactly is exceeding its allowed time?
Would love to get some feedback on this so I can prevent this from happening.
Thanks a lot for any help and have a nice day!
The listening callbacks were not triggered for intervalDidStart and intervalDidEnd after successfully starting center.startMonitoring when I attempted to set a schedule with DeviceActivitySchedule at 20-minute intervals
Is there anyone who can assist me? Thank you.
Below you will find my code.
let intervalLengthInSeconds = 20 * 60
let intervalEnd = Date(timeIntervalSinceNow: TimeInterval(intervalLengthInSeconds))
let intervalStart = Date()
let schedule = DeviceActivitySchedule(intervalStart: Calendar.current.dateComponents([.hour, .minute], from: intervalStart),
intervalEnd: Calendar.current.dateComponents([.hour, .minute], from: intervalEnd),
repeats: false,
warningTime: DateComponents(minute: 1))
let newActivity = DeviceActivityName(rawValue: "20minuteUse")
Log("😯 \(String(describing: schedule.nextInterval))")
do {
try center.startMonitoring(newActivity, during: schedule)
} catch {
print("failed to start session: \(error.localizedDescription)")
}
class MyMonitorExtension: DeviceActivityMonitor {
let store = ManagedSettingsStore()
// You can use the `store` property to shield apps when an interval starts, ends, or meets a threshold.
override func intervalDidStart(for activity: DeviceActivityName) {
super.intervalDidStart(for: activity)
// Shield selected applications.
Log("😓 start-------")
}
override func intervalDidEnd(for activity: DeviceActivityName) {
super.intervalDidEnd(for: activity)
Log("😓 end-------")
}
override func intervalWillStartWarning(for activity: DeviceActivityName) {
super.intervalWillStartWarning(for: activity)
Log("😓 StartWarning-------")
}
override func intervalWillEndWarning(for activity: DeviceActivityName) {
super.intervalWillEndWarning(for: activity)
Log("😓 EndWarning-------")
}
}
schedule.nextInterval ------ print:
😯 Optional(2024-06-21 08:34:00 +0000 to 2024-06-21 08:54:00 +0000)
We are using the Apple ScreenTime API for monitoring the usage of device. As mentioned in the documentation (https://developer.apple.com/documentation/familycontrols), we are getting the family controls authorisation from the user. We also have added the ‘DeviceActivityMonitor’ app extension (https://developer.apple.com/documentation/deviceactivity/deviceactivitymonitor) to receive the schedule and event callbacks.
We have a requirement in which we have to notify the user for every 15 minutes usage of the device in the specified interval. He can optionally select individual categories or applications for the 15 minutes notification. For monitoring the usage for individual categories or applications, we obtain the token by presenting the FamilyActivityPicker as discussed in this documentation https://developer.apple.com/documentation/familycontrols/familyactivitypicker.
For simplicity in testing during the development phase, we reduced the 15 minutes to 2 minutes. The events callbacks are expected to be delivered as soon as the threshold is reached but there are some inconsistencies with the event threshold callbacks. Sometimes the event callbacks are deferred and delivered together, sometimes the event callbacks are not delivered at all, sometimes a few event callbacks are missed etc.
Brief & History
Since iOS 17.4 and up we experience a lot of flakyness when it comes to DeviceActivity event thresholds. After a lot of testing and investigations inside system logs and filing countless bug reports we found a reproducible way why the event thresholds are not getting properly called.
Findings
Apparently when the device reaches near to max memory something called jetsamkills processes left and right.
This means that the UsageTrackingAgent that (we think) is responsible for tracking the usage time of the device gets killed and doesn't recover until significant memory is freeing up on the device.
How to test it yourself
Use a slightly older device with ~ 3 or 4 GB of RAM
Open a game or two that is meomry intensive (like Fishing Clash, yes..) and observe
In the console logs you see something that only happens then:
Process UsageTrackingAgent [39307] killed by jetsam reason highwater
This happens often but recovers itself when the UsageTrackingAgent exceeds their 6MB memory limit. Yet the log looks like this:
Process UsageTrackingAgent [39307] killed by jetsam reason per-process limit
Once you kick the game, the memory is free and sometimes the event thresholds are calling in again.
Defeating the purpose
However this defeats the purpose of tracking usage time and shielding perhaps the playing app from being played after a certain amount of time!
Feedback Assistant Ticket
Here is the ticket with sysdiagnose, step by step and more information: FB13884981
Please fix this ASAP, this is such a pain for production users and their kids EVERY DAY.
Hello,
I want to make an app purely for academia to get the app usage data which includes timestamps of app usage and I want to store this data in a MySQL database for analysis purposes. From what I have read online, I don't get access to the raw data instead I can only see the data in Views. Is there any way I can export this data outside the app? Is it even possible?
Hi, I have a released screentime app ScreenZen. The last few days I've seen a disturbing spike in bug reports coming from people with 17.4.1 and 17.5.1 phones with no update to the app itself. People reported they saw the issue immediately after updating their iOS version. Unfortunately it is not replicable on all phones with those versions, so we haven't been able to replicate it on our test phones.
It appears the issue is the ApplicationToken passed into ShieldActionExtension and ShieldConfigurationExtension does not match any of the ApplicationTokens that the user selected to block through FamilyControls. (The selected ApplicationTokens are being loaded through a group UserDefaults and they are indeed being loaded in the ShieldActionExtension in the bug reports).This is preventing the app from loading the correct settings and handling the blocking accordingly. I am trying to isolate this better with a new release with better logging, but would appreciate any help on this issue.
I'm building an iOS app using Swift, designed to run on iOS 16 and later and I'm curious about accessing battery health information directly from the device. Specifically, I'm interested in retrieving details such as the maximum battery capacity and app usage statistics for my application.
Is it possible to programmatically obtain this data within my app?
Any guidance would be helpful. Thank you for your assistance!"
Hello,
I'm working on an app that makes use of Screen Time features by leveraging the Family Controls, Device Activity and Managed Settings frameworks.
The main app works fine by shielding/unshielding apps with a toggle.
When it comes to monitoring the time intervals with the Device Activity Monitor (DAM) extension (e.g. lock X apps for Y minutes), I'm experiencing several issues.
To shield/unshield apps and kick off the monitoring I perform the following instructions:
let timeInMinutes = 15
let startDate = Date(timeIntervalSinceNow: 1.0) // padding added to avoid invalid DAM ranges < 15 mins.
let endDate = startDate.addingTimeInterval(timeInMinutes * 60.0)
let components: Set<Calendar.Component> = [.day, .month, .year, .hour, .minute, .second]
let calendar = Calendar.current
let intervalStart = calendar.dateComponents(components, from: startDate)
let intervalEnd = calendar.dateComponents(components, from: endDate)
let schedule = DeviceActivitySchedule(intervalStart: intervalStart, intervalEnd: intervalEnd, repeats: false)
try deviceActivityCenter.startMonitoring(.definiteShield, during: schedule)
let managedSettingsStore = ManagedSettingsStore()
managedSettingsStore.shield.applications = selection.applicationTokens // `selection` being an instance of `FamilyActivitySelection`
The main pain points are:
After this code is performed, I would expect the Device Activity Monitor extension to start, or at least to start once I go to background. To check whether the DAM extension is running or not, I attach to the extension process manually (Product > Attach to Process by PID or Name). But I can see the extension correctly running only after 3-4 attempts of calling startMonitoring.
Even when the DAM extension runs, intervalDidStart and intervalDidEnd methods in the extension are called quite randomly - most of the times not being called at all - thus making the extension hugely unaffordable.
Please note:
I already ask for Screen Time permissions during the onboarding by calling AuthorizationCenter.shared.requestAuthorization(for: .individual), so by the time the user shields the apps, these permissions are already granted.
I already have Family Control entitlements for development and distribution, and for both the main target and the DAM extension target.
In the intervalDidEnd method, I simply call ManagedSettingsStore().clearAllSettings() and DeviceActivityCenter().stopMonitoring(). This looks like to be enough to stay way below the 6MB memory limit.
Am I doing something wrong, is there a way to fix this, or is just the Device Activity framework that is unstable?
I added debug break point to the first line of MyDeviceActivityMonitor.swift, it never got trigger.
I am able to launch the app, select discouraged and encouraged app.
discouraged apps are getting restricted which is expected. but device activity extension is never called.
I have all the permission and certificate. I created an app group.
import SwiftUI
import FamilyControls
import ManagedSettings
@main
struct GetALifeApp: App {
@UIApplicationDelegateAdaptor(AppDelegate.self) private var appDelegate
@StateObject var model = MyModel.shared
@StateObject var store = ManagedSettingsStore()
var body: some Scene {
WindowGroup {
ContentView()
.environmentObject(model)
.environmentObject(store)
}
}
}
class AppDelegate: NSObject, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool {
initiateAsyncSetup()
MySchedule.setSchedule()
return true
}
private func initiateAsyncSetup() {
Task {
do {
try await AuthorizationCenter.shared.requestAuthorization(for: .individual)
} catch {
print("Error during asynchronous setup: \(error)")
}
}
}
}
import Foundation
import FamilyControls
import ManagedSettings
private let _MyModel = MyModel()
class MyModel: ObservableObject {
let store = ManagedSettingsStore()
@Published var selectionToDiscourage: FamilyActivitySelection
@Published var selectionToEncourage: FamilyActivitySelection
init() {
selectionToDiscourage = FamilyActivitySelection()
selectionToEncourage = FamilyActivitySelection()
}
class var shared: MyModel {
return _MyModel
}
func setShieldRestrictions() {
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)
}
}
import Foundation
import DeviceActivity
extension DeviceActivityName {
static let daily = Self("daily")
}
extension DeviceActivityEvent.Name {
static let encouraged = Self("encouraged")
}
let schedule = DeviceActivitySchedule(
intervalStart: DateComponents(hour: 0, minute: 0),
intervalEnd: DateComponents(hour: 23, minute: 59),
repeats: true
)
class MySchedule {
static public func setSchedule() {
print("Setting schedule...")
print("Hour is: ", Calendar.current.dateComponents([.hour, .minute], from: Date()).hour!)
let events: [DeviceActivityEvent.Name: DeviceActivityEvent] = [
.encouraged: DeviceActivityEvent(
applications: MyModel.shared.selectionToEncourage.applicationTokens,
threshold: DateComponents(second: 2)
)
]
let center = DeviceActivityCenter()
do {
print("Try to start monitoring...")
print(events)
try center.startMonitoring(.daily, during: schedule, events: events)
} catch {
print("Error monitoring schedule: ", error)
}
}
}
import SwiftUI
struct ContentView: View {
@State private var isDiscouragedPresented = false
@State private var isEncouragedPresented = false
@EnvironmentObject var model: MyModel
var body: some View {
VStack {
Button("Select Apps to Discourage") {
isDiscouragedPresented = true
}
.familyActivityPicker(isPresented: $isDiscouragedPresented, selection: $model.selectionToDiscourage)
Button("Select Apps to Encourage") {
isEncouragedPresented = true
}
.familyActivityPicker(isPresented: $isEncouragedPresented, selection: $model.selectionToEncourage)
}
.onChange(of: model.selectionToDiscourage) {
MyModel.shared.setShieldRestrictions()
}
.onChange(of: model.selectionToEncourage) {
MySchedule.setSchedule()
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
.environmentObject(MyModel())
}
}
import Foundation
import DeviceActivity
import ManagedSettings
class MyDeviceActivityMonitor: DeviceActivityMonitor {
let store = ManagedSettingsStore()
override func intervalDidStart(for activity: DeviceActivityName) {
print("intervalDidStart")
super.intervalDidStart(for: activity)
store.shield.applications = nil
print("intervalDidStart")
}
override func intervalDidEnd(for activity: DeviceActivityName) {
super.intervalDidEnd(for: activity)
}
override func eventDidReachThreshold(_ event: DeviceActivityEvent.Name, activity: DeviceActivityName) {
super.eventDidReachThreshold(event, activity: activity)
print("used encouraged")
store.shield.applications = nil
}
override func intervalWillStartWarning(for activity: DeviceActivityName) {
super.intervalWillStartWarning(for: activity)
// Handle the warning before the interval starts.
}
override func intervalWillEndWarning(for activity: DeviceActivityName) {
super.intervalWillEndWarning(for: activity)
// Handle the warning before the interval ends.
}
override func eventWillReachThresholdWarning(_ event: DeviceActivityEvent.Name, activity: DeviceActivityName) {
super.eventWillReachThresholdWarning(event, activity: activity)
// Handle the warning before the event reaches its threshold.
}
}
I am new to swift. This is my first app. What an i doing wrong.
Device activity monitor extension is never being called.
When i launch the app, I am able to pick the discouraged and encouraged apps.
It immediately restrict the discouraged app which is expected. But the extension is never called.
import SwiftUI
import FamilyControls
import ManagedSettings
@main
struct GetALifeApp: App {
@UIApplicationDelegateAdaptor(AppDelegate.self) private var appDelegate
@StateObject var model = MyModel.shared
@StateObject var store = ManagedSettingsStore()
var body: some Scene {
WindowGroup {
ContentView()
.environmentObject(model)
.environmentObject(store)
}
}
}
class AppDelegate: NSObject, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool {
initiateAsyncSetup()
return true
}
private func initiateAsyncSetup() {
Task {
do {
try await AuthorizationCenter.shared.requestAuthorization(for: .individual)
MySchedule.setSchedule()
} catch {
print("Error during asynchronous setup: \(error)")
}
}
}
}
import Foundation
import FamilyControls
import ManagedSettings
private let _MyModel = MyModel()
class MyModel: ObservableObject {
let store = ManagedSettingsStore()
@Published var selectionToDiscourage: FamilyActivitySelection
@Published var selectionToEncourage: FamilyActivitySelection
init() {
selectionToDiscourage = FamilyActivitySelection()
selectionToEncourage = FamilyActivitySelection()
}
class var shared: MyModel {
return _MyModel
}
func setShieldRestrictions() {
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)
}
}
import Foundation
import DeviceActivity
extension DeviceActivityName {
static let daily = Self("daily")
}
extension DeviceActivityEvent.Name {
static let encouraged = Self("encouraged")
}
let schedule = DeviceActivitySchedule(
intervalStart: DateComponents(hour: 0, minute: 0),
intervalEnd: DateComponents(hour: 23, minute: 59),
repeats: true
)
class MySchedule {
static public func setSchedule() {
print("Setting schedule...")
print("Hour is: ", Calendar.current.dateComponents([.hour, .minute], from: Date()).hour!)
let events: [DeviceActivityEvent.Name: DeviceActivityEvent] = [
.encouraged: DeviceActivityEvent(
applications: MyModel.shared.selectionToEncourage.applicationTokens,
threshold: DateComponents(second: 2)
)
]
let center = DeviceActivityCenter()
do {
print("Try to start monitoring...")
try center.startMonitoring(.daily, during: schedule, events: events)
} catch {
print("Error monitoring schedule: ", error)
}
}
}
import SwiftUI
struct ContentView: View {
@State private var isDiscouragedPresented = false
@State private var isEncouragedPresented = false
@EnvironmentObject var model: MyModel
var body: some View {
VStack {
Button("Select Apps to Discourage") {
isDiscouragedPresented = true
}
.familyActivityPicker(isPresented: $isDiscouragedPresented, selection: $model.selectionToDiscourage)
Button("Select Apps to Encourage") {
isEncouragedPresented = true
}
.familyActivityPicker(isPresented: $isEncouragedPresented, selection: $model.selectionToEncourage)
}
.onChange(of: model.selectionToDiscourage) { newSelection in
MyModel.shared.setShieldRestrictions()
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
.environmentObject(MyModel())
}
}
import Foundation
import DeviceActivity
import ManagedSettings
class MyDeviceActivityMonitor: DeviceActivityMonitor {
let store = ManagedSettingsStore()
override func intervalDidStart(for activity: DeviceActivityName) {
print("intervalDidStart")
super.intervalDidStart(for: activity)
store.shield.applications = nil
print("intervalDidStart")
}
override func intervalDidEnd(for activity: DeviceActivityName) {
super.intervalDidEnd(for: activity)
}
override func eventDidReachThreshold(_ event: DeviceActivityEvent.Name, activity: DeviceActivityName) {
super.eventDidReachThreshold(event, activity: activity)
print("used encouraged")
store.shield.applications = nil
}
override func intervalWillStartWarning(for activity: DeviceActivityName) {
super.intervalWillStartWarning(for: activity)
// Handle the warning before the interval starts.
}
override func intervalWillEndWarning(for activity: DeviceActivityName) {
super.intervalWillEndWarning(for: activity)
// Handle the warning before the interval ends.
}
override func eventWillReachThresholdWarning(_ event: DeviceActivityEvent.Name, activity: DeviceActivityName) {
super.eventWillReachThresholdWarning(event, activity: activity)
// Handle the warning before the event reaches its threshold.
}
}
I am using the DeviceActivityMonitor eventDidReachThreshold functionality, but it became very unreliable on the iOS 17.5 beta.
Anyone experiencing similar problems?
Any known workarounds?
There is an inconsistent issue when views are rendered from the Device Activity Report Extension. This issue is noticeable only on release versions and it works fine in debug mode.
Around 80% of the times, the Report Views return blank screen and this is only the case when a weekly/monthly filter is used. Although, it works as expected for daily report views.
My questions are:
How are all the Report Activity Views working fine in debug mode but not in release mode?
How the daily activity filter works fine in the release mode but the weekly/monthly filters don't work? Is this because of a memory limit issue in the extension?
As of now, I have the family-controls(distribution) entitlement only for the app and for the extensions I only have family-controls(development) entitlement. Do I need to request for family-controls(Distribution) entitlement even for the extensions?
I have seen threads on the forum mentioning the blank screen issue associated with the DeviceActivityReport but haven't found a solution to it. Any suggestions/feedback would be of great help, thanks.
I've been working with the Screen Time API for almost 6 months now.
I found out it's completely unreliable, testing on iOS 17.4, the DeviceActivityReport is not showing, the DeviceActivityMonitor more often than not does not fire intervalDidStart. It's very frustrating.
Has anyone found out a workaround?
We all know there has to be something we're doing wrong, since apps like Opal and Jono does not present those types of issues.
Let's please unite our forces and find a solution. How to use this API should not be a secret!