Device Activity

RSS for tag

Monitor web and app usage through custom time windows and events.

Posts under Device Activity tag

98 Posts
Sort by:
Post not yet marked as solved
0 Replies
127 Views
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. } }
Posted Last updated
.
Post not yet marked as solved
0 Replies
73 Views
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. } }
Posted Last updated
.
Post not yet marked as solved
3 Replies
617 Views
Hello, I wasn't able to figure out how to handle multiple days with DeviceActivitySchedule. For instance, let's say the user wants to block certain apps from 9:00 AM to 12:00 AM, every day except Saturday and Sunday, how my schedule should look like? I've tried different things... This schedule works for each day of the week, but that's not my goal: let schedule = DeviceActivitySchedule( intervalStart: DateComponents(hour: 9, minute: 00), intervalEnd: DateComponents(hour: 12, minute: 00), repeats: true) And if I specify the weekDay inside the DateComponents, like this: // Gregorian calendar // 2 -> Monday // 6 -> Friday let schedule = DeviceActivitySchedule( intervalStart: DateComponents(..., weekday: 2), intervalEnd: DateComponents(..., weekday: 6), repeats: true) the schedule will block the apps from Monday at 9:00 AM to Friday at 12:00 AM, which is also not my goal. The only workaround that came to my mind was to create a different schedule for each day of the week: enum WeekDays: String, CaseIterable { case sun, mon, tue, wed, thu, fri, sat var sortOrder: Int { switch self { case .sun: return 1 case .mon: return 2 case .tue: return 3 case .wed: return 4 case .thu: return 5 case .fri: return 6 case .sat: return 7 } } } func startMonitoring(weekDays: [WeekDays]) { for weekDay in weekDays { let day = weekDay.sortOrder let schedule = DeviceActivitySchedule( intervalStart: DateComponents( hour: 9, minute: 00, weekday: day), intervalEnd: DateComponents( hour: 12, minute: 00, weekday: day), repeats: true) let activityName = DeviceActivityName(weekDay.rawValue) do { try center.startMonitoring(activityName, during: schedule) } catch { print("DEBUG: Error: \(error.localizedDescription)") } } } This way I kinda get what I want, for example: I can specify 3 days of the week, let's say Monday, Tuesday and Wednesday, the time interval, let's keep 9:00 AM - 12:00 AM, and this function will block apps on Monday, Tuesday and Wednesday at that time interval, fine. However... What if I also want another schedule that blocks at a different time interval but same day? For example, I want to block certain apps Monday and Tuesday from 2:00 PM - 6:00 PM. Following the example above the activityName would be overwritten, so the user ( for Monday and Tuesday ) would now have only the schedules that starts from 2:00 PM. Basically, I want the user to be able to select multiple days for a schedule and to let them create as many schedules as they want. Does anybody know the correct way to handle multiple days schedules?
Posted
by Ivan018.
Last updated
.
Post not yet marked as solved
7 Replies
2.2k Views
When I tap on one of the buttons in the ShieldAction extension I want to close the shield and open the parent app instead of the shielded app. Is there any way of doing this using the Screen Time API? class ShieldActionExtension: ShieldActionDelegate {      override func handle(action: ShieldAction, for application: ApplicationToken, completionHandler: @escaping (ShieldActionResponse) -> Void) {     // Handle the action as needed.           let store = ManagedSettingsStore()               switch action {     case .primaryButtonPressed:       //TODO - open parent app       completionHandler(.defer)     case .secondaryButtonPressed:       //remove shield       store.shield.applications?.remove(application)       completionHandler(.defer)         @unknown default:       fatalError()     }   }   }
Posted
by mariusgab.
Last updated
.
Post not yet marked as solved
0 Replies
146 Views
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.
Posted Last updated
.
Post not yet marked as solved
1 Replies
169 Views
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!
Posted
by Ivan018.
Last updated
.
Post not yet marked as solved
2 Replies
497 Views
Using the DeviceActivity framework we are able to display data based on a user's screentime and device usage. With the DeviceActivityFilter property, you can specify the date interval to collect data between. In testing, it seems that data only becomes accessible once the extension has been installed (so the extension isn't reading the screentime data already collected on device). However, once installed, I'm curious how far back you can query data from in the data interval? Opal which uses the Screentime API appears to have a lifetime Screentime metric, so hypothetically it should possible to query data as far back as collection starts. Unless they are getting around the sandbox environment and storing the data somehow. Side note on Opal -- They seem to have a community average of Screentime among people in the same age group. Does anyone know how they are collecting the data for this average? Is it actually using live Screentime data or just aggregating data from other studies?
Posted Last updated
.
Post not yet marked as solved
1 Replies
635 Views
Our app uses DeviceActivityReport to display the user’s screen time. The performance of DeviceActivityReport is often very poor. These issue occur commonly: Screen time is reported as 0 minutes DeviceActivityReport View appears completely blank The host app loses connection with the DeviceActivityReport altogether I have implemented several workarounds which only slightly improve the performance, to varying degrees depending on the device iOS: Inside the DeviceActivityReport code - retry fetching screen time data until it returns a non-zero result Implement a “refresh” button which reloads the DeviceActivityReport view from the host app However, due to the sandboxed nature of DeviceActivityReport, there is no way for the host application to tell if the DeviceActivityReport extension is experiencing these performance issues. It results in a really bad user experience. I am building the app with Xcode 14 due to another issue where DeviceActivityReport fails to load for all iOS 16 devices when built with Xcode 15 (this is a know issue, here’s a link to a discussion on the developer forums: https://developer.apple.com/forums/thread/735915). However, when testing on iOS 17 devices with Xcode 15 builds, the above issues still occur. I have received no crash reports from DeviceActivityReport. These issues are known bugs and have been discussed on the developer forums, but I haven't yet seen a solution. Other screen time apps exist that use the DeviceActivityReport seemingly flawlessly, so I know that there is a way to improve the performance of DeviceActivityReport in my app. Please help! I have been dealing with this poor performance for a long time now with almost no improvement!
Posted Last updated
.
Post marked as solved
2 Replies
1.1k Views
There is frequently a delay of a few seconds before a DeviceActivityReport renders its view generated from the DeviceActivityReportExtension. It will also sometimes flash with zero data before hydrating with the real activity data (tested with extension code taken directly from XCode boilerplate) Is there a way to be notified when the DeviceActivityReport renders successfully or is still processing, i.e. so a loading indicator can be presented while the extension runs? Thanks!
Posted
by foijodsf.
Last updated
.
Post not yet marked as solved
2 Replies
860 Views
There have been several posts (i.e. here, here) about the lagginess of the DeviceActivityReport extension. Often it takes a few seconds for the view to load, or sometimes doesn't show up at all. I've confirmed this is not a case of excessive memory usage in the extension (exceeding 100MB), because I've profiled the extension and it consistently maxes out at 10MB. I've placed a loading screen behind the DeviceActivityReport inside a ZStack in the host app in order to see if the lag is because it takes some time for the extension to spin up - but the loading screen does not appear, indicating that the extension is running right away, but receiving the view from the extension in the host app is where the lag happens. It's been extremely difficult to debug because the lag only occurs a fraction of the time, and DeviceActivityReport is pretty much a black box. There's no documentation about how the host app and extension actually communicate. I've also combed through the logs using the Console app on Mac with no indication of any issues, (but I do see the message "Connection to view service was invalidated" coming from the extension even when there is no lag). I'm pretty convinced that the problem lies in the host app, because when I strip everything away from the host app, DeviceActivityReport never lags. I suspect that there are processes running (network requests, async tasks, or state updates) that block the report view from being received in the host app. Could you please help me understand why this could be happening, with as many details as you could provide? Any details on how the host and extension communicate, what processes could block the view from appearing, or anything else. Seems like this is a common issue but plenty of apps also don't experience it. Any guidance you can provide would be extremely helpful, as I've been trying to fix this bug every since I've been working with this API with no luck. Thanks in advance!
Posted Last updated
.
Post not yet marked as solved
0 Replies
115 Views
I have a request from a client that would like to create a solution where a central component is the ability to retrieve the users app usage. I can see that there are various api's todo that - one example is the Device Activity API. Another hope from the client is that this should be a web solution and not an app. I haven't quite been able to figure out if this is possible or not. I have three questions: Is it possible to retrieve app usage information through a REST api (or similar) outside an iOS app? Is it possible to use the appleId as a kind of auth solution for a web application Are there any similar APIs for older versions than iOS 15?
Posted
by andersbe.
Last updated
.
Post not yet marked as solved
0 Replies
148 Views
How can I differentiate between multiple children in order to display screentime data to the user separately for a parent with multiple children? As far as I can see, the options are .children, and .all? I understand I can retrieve some info from within the extension so I can group data separately, but is there any way to reliably filter between different children from within my app, say using a DeviceActivityFilter? Many thanks!
Posted
by op1490.
Last updated
.
Post not yet marked as solved
0 Replies
177 Views
I am currently debugging an issue with DeviceActivityMonitor where the threshold is reached even though the target app (e.g. Instagram) is not being used actively. I noticed that the device with the unexpected behavior had the instagram.com website opened in the Safari web browser (among hundreds of other tabs). That tab was not actively used either (not in foreground, Safari app neither used). However, I was wondering if it can happen that this website is contributing towards the threshold as well even though it is in background and not used? Otherwise I cannot explain myself this strange behavior.
Posted
by Quappi.
Last updated
.
Post not yet marked as solved
2 Replies
725 Views
currently when I try to set several schedules to the same activity the latest schedule I set is the only one I understand I can have only 1 schedule for activity. ? I thought about setting a new schedule on the intervalDidEnd but, I get no interval did start if the current time is in the middle of the interval I set For example, now it is 15:00, and my previous interval started at 14:00 and ends at 16:00 but the user sets a new interval from 14:30 - 16:40 I call the deviceActivityCenter.stopMonitoring([someActivityName]) and get noIntervalDidEnd event Then I set the new interval successfully with deviceActivityCenter.startMonitoring(someActivityName, during: deviceActivitySchedule) and get no intervalDidStartEvent So how can I achieve several intervals? If I had gotten the events of the start and end it would be possible Thanks for the help
Posted
by Boaz F..
Last updated
.
Post not yet marked as solved
5 Replies
647 Views
The device activity monitor extension sometimes fails to launch when a schedule starts/ends or when an event threshold is reached. This issue may persist for several minutes or hours once it begins. Currently, the only known workarounds are: Restarting the phone. Waiting for an indeterminate period, ranging from a few minutes to hours, after which the device activity extension may or may not launch. I've filed a new bug report (FB13556935), which includes a sysdiagnose and precise timestamps of when the issue was reproduced. By looking at the errors, it appears the system is failing to launch the extension because it's looking at an invalid path: Service could not initialize: access(/private/var/containers/Bundle/Application/C6598B47-8977-447C-870B-4D21BDE8ACF9/Jomo.app/PlugIns/JomoDeviceActivityMonitor.appex/JomoDeviceActivityMonitor, X_OK) failed with errno 2 - No such file or directory, error 0x6f - Invalid or missing Program/ProgramArguments [u 8104FF60-5C49-45BD-8AFB-97BE88488134:m (null)] [()] Failed to start plugin; pkd returned an error: Error Domain=PlugInKit Code=4 "RBSLaunchRequest error trying to launch plugin com.jomo.Jomo.JomoDeviceActivityMonitor(8104FF60-5C49-45BD-8AFB-97BE88488134): Error Domain=RBSRequestErrorDomain Code=5 "Launch failed." UserInfo={NSLocalizedFailureReason=Launch failed., NSUnderlyingError=0x5dd8273e0 {Error Domain=NSPOSIXErrorDomain Code=111 "Unknown error: 111" UserInfo={NSLocalizedDescription=Launchd job spawn failed}}}" UserInfo={NSLocalizedDescription=RBSLaunchRequest error trying to launch plugin com.jomo.Jomo.JomoDeviceActivityMonitor(8104FF60-5C49-45BD-8AFB-97BE88488134): Error Domain=RBSRequestErrorDomain Code=5 "Launch failed." UserInfo={NSLocalizedFailureReason=Launch failed., NSUnderlyingError=0x5dd8273e0 {Error Domain=NSPOSIXErrorDomain Code=111 "Unknown error: 111" UserInfo={NSLocalizedDescription=Launchd job spawn failed}}}} This bug is CRITICAL for all apps relying on the Device Activity framework. It likely explains a range of issues reported since the framework's release. Specifically, due to this bug, end users may encounter problems such as apps not unblocking at the end of a schedule, apps not blocking at the start of a schedule, and time limits not being updated, among others.
Posted Last updated
.
Post not yet marked as solved
2 Replies
302 Views
As per our code, we have the apps to be shielded whenever the threshold is reached. According to this use-case, our code in DeviceActivityExtension looks something like: override func eventDidReachThreshold(_ event: DeviceActivityEvent.Name, activity: DeviceActivityName) { super.eventDidReachThreshold(event, activity: activity) defaults?.setValue(event.rawValue, forKey: "appLimitEventName") defaults?.setValue(true, forKey: "appLimitReached") defaults?.synchronize() // using darwinNotificationCenter to trigger callback in the application let darwinNotificationCenter = DarwinNotificationsManager.sharedInstance() darwinNotificationCenter.postNotification(withName: "nextAppLimitInitiated") // using Notifications to debug since print doesn't work scheduleNotification(with: "interval threshold reached") } And in our application, we have the shielding logic in place, init() { let darwinNotificationCenter = DarwinNotificationsManager.sharedInstance() darwinNotificationCenter.register(forNotificationName: "nextAppLimitInitiated"){ print("callback received") let appLimitReached = self.defaults?.bool(forKey: "appLimitReached") let appLimitEventName = self.defaults?.string(forKey: "appLimitEventName") if appLimitReached ?? false, appLimitEventName != "" { // this sends the notification when callback is received self.scheduleNotification(with: "init start") self.defaults?.setValue(false, forKey: "appLimitReached") guard var dataArray = self.defaults?.array(forKey: "appLimitdataArray"), !dataArray.isEmpty else { return } let appLimitData = dataArray.first as! NSDictionary let appLimitKey = appLimitData["appLimitId"] as! String let data = self.getSchedule(key: appLimitEventName ?? "") if let appTokens = data?.applicationTokens { for token in appTokens { if !self.applicationTokens.contains(appTokens) { self.applicationTokens.insert(token) } } } self.store.shield.applications = self.applicationTokens self.store.shield.applicationCategories = ShieldSettings.ActivityCategoryPolicy.specific(self.categoryTokens, except: Set()) dataArray.removeFirst() //dataArray.append(appLimitData) self.defaults?.set(dataArray, forKey: "appLimitdataArray") self.initiateMonitoring(initiateAgain: true) self.scheduleNotification(with: "init end") } } } This works as expected for multiple App Limits but only when the device is connected to the Xcode. If we disconnect the device from Xcode/ stop application from Xcode/ try in release mode, the callback is not received from extension to the app/init block. When the device is connected to Xcode, if the apps hit the threshold, they are shielded automatically. But if the device is disconnected/ app is in release mode, the apps are not shielded automatically even after the threshold is reached. It is shielded later only after opening our app once. Please let me know if I'm doing anything wrong in receiving callback or in my shielding logic. If I need to place the shielding logic in the extension, please tell me how I can handle multiple appTokens.
Posted Last updated
.
Post marked as solved
1 Replies
376 Views
I am trying to understand how to approach 'x minute' pauses for a DeviceActivitySchedule. For instance, I would like to let the user pause for 5 minutes from an active schedule (meaning un-shielding the apps and re-applying the shield after the 5 min has passed). The only way that came to my mind was calling the following: Calling .startMonitoring to start monitoring a new event with the same apps starting .now and ending .now + 5 minutes; Calling in the intervalDidStart, store.shield.applications.subtract(apps) so that the apps are removed from the shield. Calling in the intervalDidEnd, store.shield.applications = apps so that the apps are now shielded again. The problem is that, from the Apple Developer Documentation: The minimum interval length for monitoring device activity is fifteen minutes. So the minimum pause I could offer to the user would be 15 minutes. And that tells me this approach is most likely wrong, because all other Screen Time apps, like Opal, Jomo, AppBlock offer also 5 min pause. Does anyone know / can think of a different and better approach?
Posted
by Ivan018.
Last updated
.
Post not yet marked as solved
0 Replies
191 Views
I have two repeating DeviceActivitySchedules running in my app and noticed a super strange behavior: whenever I modify Screen Time API permission settings (granting an additional app permission, or removing permission for a different app (completely different unrelated screen time apps from App Store)) all my DeviceActivitySchedules are cancelled and the intervalDidEnd callbacks are called my permission is not modified in this scenario this is a super strange and unexpected behavior is anyone able to reproduce this? for me this happens 100% of the times I do this any known workarounds?
Posted
by Quappi.
Last updated
.
Post not yet marked as solved
0 Replies
197 Views
How can I count the number of pickups for a certain application? The docs say that there is a struct ApplicationActivity within the DeviceActivityData: https://developer.apple.com/documentation/deviceactivity/deviceactivitydata Using this code I receive a warning in XCode: Value of type 'DeviceActivityData' has no member 'applicationActivity' struct ApplicationPickupCountReport: DeviceActivityReportScene { // Define which context your scene will represent. let context: DeviceActivityReport.Context = .applicationPickupCount // Define the custom configuration and the resulting view for this report. let content: (String) -> ApplicationPickupCountView func makeConfiguration(representing data: DeviceActivityResults<DeviceActivityData>) async -> String { var totalPickups = 0 let totalPickups = await data.flatMap { $0.applicationActivity }.reduce(0, { $0 + $1.numberOfPickups }) return "\(totalPickups)" } }
Posted
by Flowco.
Last updated
.