Device Activity

RSS for tag

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

Posts under Device Activity tag

96 Posts
Sort by:
Post not yet marked as solved
0 Replies
217 Views
Hello, I am using a DeviceActivityEvent to limit access to an app after the user has spent x minutes on it. Sometimes it can happen that a DeviceActivitySchedule spans from 11:55pm - 12:25am (just an example). In these cases, I have noticed, the DeviceActivityMonitorExtension’s eventDidReachThreshold is not called after the user has reached the threshold time interval in the observed app. I assume this is because we have transitioned over midnight and something weird happens to the DeviceActivitySchedule. I’ve tried adding the day components to the DeviceActivitySchedule as well, but then it fails completely. Any advice how to handle this? I could, of course, create two separate DeviceActivitySchedules: one for before midnight, and one for after. But depending on the user’s real app usage that could lead to slightly different (and unexpected) behavior.
Posted
by Quappi.
Last updated
.
Post not yet marked as solved
0 Replies
178 Views
Hello! I am using the eventDidReachThreshold callback in the DeviceActivityMonitor in order to shield a target app after the user has spend x amount of time on it (e.g. x = 5 minutes). Many times this works fine, and I can trigger my shield after the specified threshold has been met. However sometimes, when they leave the target app before the threshold has been reached, the eventDidReachThreshold callback gets called randomly while they are doing something else on their phone (e.g. using a different app, on the Home Screen, phone locked…). From my perspective this does not make sense, since they are not actively spending time on the target app, and that time should not be counted towards the target app’s threshold. And it is also very confusing for the users because they will then find a blocked target app even though they haven’t used their time budget completely. This is not related to the intervalDidStart / intervalDidEnd callbacks, because they are not correlating with the timing of when the eventDidReachThreshold callback is called unexpectedly. Any ideas what this could be related to?
Posted
by Quappi.
Last updated
.
Post not yet marked as solved
3 Replies
826 Views
Hi there, In rare cases (about 0.2% of the time?), I'm seeing calls to startMonitoring on an instance of DeviceActivityCenter throw an error with localizedDescription "couldn’t communicate with a helper application." I am certain I am passing valid parameters to the startMonitoring call because sometimes a naive retry after a few seconds succeeds. Similarly, I am certain that FamilyControls permissions have been granted by the user. Was hoping to get more color from the systems team on what some causes of this error are and if it is avoidable by the programmer.
Posted Last updated
.
Post not yet marked as solved
1 Replies
699 Views
Starting with iOS 17.4, the DeviceActivityEvent initializer includes a new parameter named includesPastActivity.

The default value for this parameter is set to false, whereas device activity events have behaved as though this parameter were set to true up until now. This breaking change is a MAJOR ISSUE for developers who used device activity events in their apps before iOS 17.4 because their apps might not work the way they intended after the update. They'll have to release new app versions that specifically set includesPastActivityto true. In my opinion, the default value for includesPastActivity should be true to avoid disrupting events scheduled on older versions of iOS. I have filed an enhancement report (FB13573556) about this. I really hope this is changed before the official iOS 17.4 release.
Posted Last updated
.
Post not yet marked as solved
0 Replies
248 Views
There is a way to allow DeviceActivityMonitor to make UI changes? Currently I have some code in the intervalDidStart and intervalDidEnd that updates Core Data entities, and it works correctly. However, the changes are only reflected if the app is terminated and opened again. Thus, if the app is opened and one of the methods inside the DeviceActivityMonitor is being called, the UI won't be updated. PS: I am using @FetchRequest to retrieve the core data entities called BlockEntity, and I have a little circle in the UI which should indicate the status of the block: active/inactive, so it would be nice to update the color in real time when intervalDidStart or intervalDidEnd are called.
Posted
by Ivan018.
Last updated
.
Post not yet marked as solved
1 Replies
424 Views
I am able to correctly select and store the tokens of apps and categories my users will block, but I am unable to pre-populate Picker whenever the app is rebooted with previously selected and stored tokens. Below is the selection variable I am passing to the picker... var selectionsToBlock = FamilyActivitySelection() { willSet { saveSelection(selection: newValue) blockersSelected = true } } Is there any way I can provide my existing blockers (shown below) so that the user can easily edit their list of restricted apps from the Picker? func savedBlockers() -> FamilyActivitySelection? { let defaults = UserDefaults.standard guard let data = defaults.data(forKey: userDefaultsKey) else { return nil } return try? decoder.decode( FamilyActivitySelection.self, from: data ) }
Posted
by gweinz.
Last updated
.
Post not yet marked as solved
2 Replies
458 Views
I am developing a project with the Screen Time API, and I cannot understand why the methods inside DeviceActivityMonitor extension are not being called. Some points to note: I do start by requesting authorization from the User (this is working as expected when opening the app) Both the DeviceActivityMonitor Extension and the main app are under the same App Group I have added Family Controls capability to both targets and have the developer account to use it. I start by calling center.startMonitoring() I have overridden the original methods. Yet, when startMonitoring is called, there is no action that is supposed to be taken that is being taken, and as far as I can tell, the methods aren't even being called. Here are some relevant snippets of code: // EXT class DeviceActivityMonitorExtension: DeviceActivityMonitor { override func intervalDidStart(for activity: DeviceActivityName) { super.intervalDidStart(for: activity) let store = ManagedSettingsStore(named: .daily) } override func intervalDidEnd(for activity: DeviceActivityName) { super.intervalDidEnd(for: activity) let store = ManagedSettingsStore(named: .daily) store.clearAllSettings() } override func eventDidReachThreshold(_ event: DeviceActivityEvent.Name, activity: DeviceActivityName) { super.eventDidReachThreshold(event, activity: activity) let store = ManagedSettingsStore(named: .daily) let model = BeeFreeModel.shared let applications = model.selectionToDiscourage.applicationTokens let categories = model.selectionToDiscourage.categoryTokens let webDomains = model.selectionToDiscourage.webDomainTokens store.shield.applications = applications.isEmpty ? nil : applications store.shield.applicationCategories = categories.isEmpty ? nil : ShieldSettings.ActivityCategoryPolicy.specific(categories) store.shield.webDomains = webDomains.isEmpty ? nil : webDomains } } // APP extension DeviceActivityName { static let daily = Self("daily") } extension DeviceActivityEvent.Name { static let discouraged = Self("discouraged") } let schedule = DeviceActivitySchedule( intervalStart: DateComponents(hour: 0, minute: 0, second: 0), intervalEnd: DateComponents(hour: 23, minute: 59, second: 59), repeats: true ) class BeeFreeSchedule { static public func setSchedule() { print("Setting schedule...") print("Hour is: ", Calendar.current.dateComponents([.hour, .minute], from: Date()).hour!) let events: [DeviceActivityEvent.Name: DeviceActivityEvent] = [ .discouraged: DeviceActivityEvent( applications: BeeFreeModel.shared.selectionToDiscourage.applicationTokens, categories: BeeFreeModel.shared.selectionToDiscourage.categoryTokens, webDomains: BeeFreeModel.shared.selectionToDiscourage.webDomainTokens, threshold: BeeFreeModel.shared.thresholdToDiscourage ) ] let center = DeviceActivityCenter() do { print("Try to start monitoring...") // Call startMonitoring with the activity name, schedule, and events try center.startMonitoring(.daily, during: schedule, events: events) } catch { print("Error monitoring schedule: ", error) } } } // APP class BeeFreeModel: ObservableObject { // Import ManagedSettings to get access to the application shield restriction let store = ManagedSettingsStore() //@EnvironmentObject var store: ManagedSettingsStore @Published var selectionToDiscourage: FamilyActivitySelection @Published var thresholdToDiscourage: DateComponents @Published var setOfApps: [String] init() { selectionToDiscourage = FamilyActivitySelection() thresholdToDiscourage = DateComponents() var setOfAppIdentifiers: Set<String?> = Set<String?>() setOfApps = [String]() if selectionToDiscourage.applicationTokens.isEmpty {} else { for application in BeeFreeModel.shared.selectionToDiscourage.applications { setOfAppIdentifiers.insert(application.localizedDisplayName) setOfApps = setOfAppIdentifiers.compactMap { $0 }.sorted() } } } class var shared: BeeFreeModel { return _BeeFreeModel } func setSelection() { let applications = BeeFreeModel.shared.selectionToDiscourage } func changeThreshold(threshold: DateComponents) { thresholdToDiscourage = threshold } } // APP /// ... Button("Select Apps to Discourage") { isDiscouragedPresented = true } .familyActivityPicker(isPresented: $isDiscouragedPresented, selection: $model.selectionToDiscourage) } .onChange(of: model.selectionToDiscourage) { BeeFreeModel.shared.setSelection() } // ... // ... Button("Save Time") { saveTime() let new_threshold = DateComponents(hour: savedTime?.hours, minute: savedTime?.minutes, second: savedTime?.seconds) model.changeThreshold(threshold: new_threshold) } } .onChange(of: model.thresholdToDiscourage) { BeeFreeSchedule.setSchedule() // ... I believe I am using the latest stable version of Xcode (recently deleted and reinstalled). I'm really new to mobile development to Swift so any help is greatly appreciated. Thank you! :)
Posted Last updated
.
Post not yet marked as solved
0 Replies
292 Views
Sometimes the app switcher doesn't show the correct shield configuration if there is like 7 or more apps in the app switcher. if I clear all apps from app switcher cache and leave 4 apps, the correct shield configuration will show every time instantly when I change the shield configuration from my parent app and go back to the app switcher; but if there is like 7 or more apps in the app switcher, I can see some of the app's shield configurations don't update instantly and I have to scroll past the app in the app switcher and go back to for it to update to the correct shield if it does at all. This is misleading to users and in the case of my app detrimental to one of its core functionalities override func configuration(shielding application: Application) -> ShieldConfiguration { let sharedUserDefaults = UserDefaults(suiteName: SharedUserDefaults.suiteName.rawValue)! let isPaidOn = sharedUserDefaults.bool(forKey: SharedUserDefaults.paidSwitchKey.rawValue) if isPaidOn == true { return ShieldConfig.paid } else { return ShieldConfig.free } }
Posted
by aus207.
Last updated
.
Post not yet marked as solved
1 Replies
352 Views
We have integrated DeviceActivityReport to our Family Controll app. All capabilities are added. We built the app and tested it, but when we want to upload to TestFlight the following error happened (see attached image) When we are adding NSExtensionMainStoryboard or NSExtensionPrincipalClass the following error appears during installation process. DeviceReport.appex with id com.example.example.DeviceReport defines either an NSExtensionMainStoryboard or NSExtensionPrincipalClass key, which is not allowed for the extension point com.apple.deviceactivityui.report-extension
Posted Last updated
.
Post not yet marked as solved
3 Replies
689 Views
Hello everyone 👋 I wanted to discuss an issue that has always been somewhat present, but seems to have become more frequent since the latest iOS 17 versions. When scheduling an activity that includes an event, the eventDidReachThreshold method does not trigger consistently within the device activity monitor extension. The issue is intermittent. However, repeating the following procedure increases the likelihood of encountering the problem: Schedule a simple activity with an event: Set the start time to the beginning of the current day and the end time to the end of the current day. Include an application token and a threshold (that you've already met for today 🙂). Once the activity is scheduled, monitor whether eventDidReachThreshold triggers in the device activity monitor extension. Workarounds I've discovered: Restart the activity: Not very reliable. Force restart the phone: A more drastic measure, but sometimes effective. Just wait: Wait for an undetermined amount of time, ranging from a few minutes to several hours, after which eventDidReachThreshold will start triggering just fine again. I've filed a bug report (FB13188666) concerning this specific issue. I'm curious to know if anyone else is experiencing it and what workarounds you've found!
Posted Last updated
.
Post not yet marked as solved
0 Replies
298 Views
Having tried to gain access to the total daily screen time API using the text/code from the below thread, we were unable to get any data access. Has anyone else had the same issue and any resolutions? Not looking for application limits, just statistics to inform user through our 3rd party application. Thanks for any guidance around areas we can attempt https://developer.apple.com/documentation/deviceactivity/deviceactivitydata/activitysegment
Posted Last updated
.
Post not yet marked as solved
3 Replies
842 Views
My app sends screen time awareness notifications based on DeviceActivityMonitor thresholds. Often, users receive two notifications in a row for the same screen time threshold. This means that the app extension is triggering the same eventDidReachThreshold callback function twice for the same threshold. I've made sure that there is only one activity schedule being monitored. This happens often, but not every time (over 50% of the time). Anybody else experience this issue, and any way to mitigate it?
Posted Last updated
.
Post not yet marked as solved
2 Replies
617 Views
Hello, I have an app that you can select apps and then start monitoring. When I restrict the apps by button click, and monitor the activity, the scheduled time works and intervalDidEnd cancels shielding apps. But when I schedule shielding apps, intervalDidStart doesn't start shielding. What am I missing here? I have already added FamilyControls capability. import SwiftUI @main struct TestingScreenTimeAPIApp: App { @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate var body: some Scene { WindowGroup { ContentView() } } } import SwiftUI struct ContentView: View { @StateObject var model = MyModel.shared @State var isPresented = false var body: some View { VStack { Button("Select Apps") { isPresented = true } .familyActivityPicker(isPresented: $isPresented, selection: $model.selectionToDiscourage) Button("Start monitoring") { model.startMonitoring() } .padding() } } } struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() } } import Foundation import FamilyControls import DeviceActivity class MyModel: ObservableObject { static let shared = MyModel() private init() {} var selection: FamilyActivitySelection? = nil var selectionToDiscourage = FamilyActivitySelection() { willSet { selection = newValue } } func startMonitoring() { let intervalStart = DateComponents(hour: 11, minute: 09) let intervalEnd = DateComponents(hour: 13, minute: 14) let schedule = DeviceActivitySchedule( intervalStart: intervalStart, intervalEnd: intervalEnd, repeats: true) let center = DeviceActivityCenter() do { try center.startMonitoring(.activity, during: schedule) } catch { print ("Error: \(error)") } } } extension DeviceActivityName { static let activity = Self("activity") } import UIKit import FamilyControls class AppDelegate: NSObject, UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool { Task { do { try await AuthorizationCenter.shared.requestAuthorization(for: .individual) } catch { print("Error: \(error.localizedDescription)") } } return true } } import DeviceActivity import FamilyControls import ManagedSettings class DeviceActivityMonitorExtension: DeviceActivityMonitor { let store = ManagedSettingsStore() override func intervalDidStart(for activity: DeviceActivityName) { super.intervalDidStart(for: activity) let model = MyModel.shared if model.selection != nil { let applications = model.selection!.applicationTokens store.shield.applications = applications.isEmpty ? nil : applications } } override func intervalDidEnd(for activity: DeviceActivityName) { super.intervalDidEnd(for: activity) store.shield.applications?.removeAll() } }
Posted
by Ismayilov.
Last updated
.
Post not yet marked as solved
8 Replies
1.2k Views
Hello Apple Developer Community, We're experiencing a critical issue with the Screen Time frameworks, and it's affecting one of our users severely. I'm hoping someone here can provide guidance or a potential solution. Details: Our app offers a feature using the ManagedSettings shield that lets users block all apps based on a set schedule. After the scheduled block ends, the apps are expected to become accessible again. In one case, a user reported that the apps did not unblock after the schedule ended. Upon trying to manually end the session from within our app, the app only displays a blank white screen. The user attempted to disable Screen Time access for our app via the iOS settings, but the apps remained blocked. Even after completely disabling Screen Time from the settings or restarting the phone, the apps stayed blocked. Interestingly, I attempted to replicate the issue on my end by toggling Screen Time settings and restarting, but everything worked as expected and I could not reproduce the problem. This issue, though seemingly isolated, has rendered a user's phone virtually unusable, and highlights a potential high-impact bug within the Screen Time framework. It feels necessary for there to be a "master off-switch" or a fail-safe mechanism in these scenarios. Any insights, solutions, or workarounds would be deeply appreciated. It's crucial for us to support our user and resolve this promptly. Thank you in advance!
Posted Last updated
.
Post not yet marked as solved
0 Replies
289 Views
I'm developing a mental wellness app, and I need to get user's screentime and app usage data and send it to my flask backend for analytics. Is it possible on iphone right now? I've looked into ScreenTime and DeviceActivity frameworks, but they're really poor in terms of examples and documentation, so I'm not sure if this is actually possible or not.
Posted
by teshnizi.
Last updated
.
Post not yet marked as solved
1 Replies
602 Views
We have an app that uses the Screen Time APIs to block certain apps set by the user on a schedule: We use ManagedSettings to shield selected apps We use DeviceActivityMonitor to shield the apps automatically on a schedule set by the user. The shielding starts during the intervalDidStart callback function and ends during the intervalDidEnd callback function We are getting reports from the majority of our iOS 17 users that the app blocking schedules no longer work on iOS 17. We have tested this on our own iOS 17 devices and reproduced the behavior. But the feature still works consistently on iOS 16 devices. The app is still built using Xcode 14 instead of Xcode 15 due to another issue - the DeviceActivityReport is blank for all iOS 16 users when built in Xcode 15 (link to issue on the developer forums: https://developer.apple.com/forums/thread/735915). When testing with Xcode 15 builds, the bug appears to improve - however it still occurs intermittently. Are there any other mechanisms to run tasks on repeating schedules? For this specific feature, we don't need to eventDidReachThreshold callbacks, which is the main purpose of DeviceActivityMonitor. So we really don't need any Device Activity integration at all, just setting and disabling ManagedSettings shields at certain times. Would love if anyone could suggest and alternative to DeviceActivityMonitor.
Posted Last updated
.
Post not yet marked as solved
1 Replies
698 Views
I use App Groups to share UserDefaults data between my host app and DeviceActivityMonitor extension. On iOS 17, it appears that reading @AppStorage variables are causing my DeviceActivityMonitor extension callback functions to crash. Weirdly, writing values is okay. I see this in the extension logs: Couldn't read values in CFPrefsPlistSource<0x10fe251d0> (Domain: GROUP_NAME, User: kCFPreferencesAnyUser, ByHost: Yes, Container: (null), Contents Need Refresh: Yes): Using kCFPreferencesAnyUser with a container is only allowed for System Containers, detaching from cfprefsd However, through searching this log message on the internet and the fact that it also appears in my host app logs without crashing, this seems to be a warning - possibly indicating an issue but also a possible red herring. But the fact remains that when I don't read UserDefaults values or variables decorated with @AppStorage in the DeviceActivityMonitor extension, everything works fine. Are UserDefaults, and specifically @AppStorage decorators supported in the DeviceActivityMonitor extension?
Posted Last updated
.
Post not yet marked as solved
0 Replies
480 Views
Hey. Is there any app that shows a precise activity log? When I was using Android I had an app Quality Time which keeps the track of what are you doing minute by minute. It has a log which shows 13:24 PM Open Facebook, 13:45 Open Instagram etc. Is there any app on iPhone that tracks your activity like this and stores it into a log or something? I need an app like this or something similar Thank you.
Posted Last updated
.
Post not yet marked as solved
0 Replies
401 Views
Any way that I try requesting authorization for family controls is incredibly inconsistent. The line of code that hangs is **let center = AuthorizationCenter.shared ** I've looked at other posts and I saw someone recommended declaring let center = AuthorizationCenter.shared outside the main thread and somehow get the status on the main thread. I've tried that approach with no success. I've scoured GitHub to see how other people approach the request but it's all pretty similar. The following code sometimes works great for a few minutes and then I rebuild and run and it hangs on AuthorizationCenter.shared.requestAuthorization(for: FamilyControlsMember.individual). Would love any suggestions!!! .onAppear { Task { do { print("try requestAuthorization") try await AuthorizationCenter.shared.requestAuthorization(for: FamilyControlsMember.individual) print("requestAuthorization success") switch AuthorizationCenter.shared.authorizationStatus { case .notDetermined: print("not determined") case .denied: print("denied") case .approved: print("approved") @unknown default: break } } catch { print("Error requestAuthorization: ", error) } } }
Posted
by adison25.
Last updated
.