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.
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
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!
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.
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)
}
}
}
Hello!
I am a new developer and am attempting to use Apple's Device Activity API. However, I am struggling with the View of the Device Activity Report. For one, the view stretches to fill all available space instead of simply being the size of its content. Secondly, the background color seems fixed and I can't figure out how to remove it. The Screen Time API demo video shows this Device Activity API used with a clear background, so I know it is possible, I just can't figure out how to do it as it seems to be built into the Device Activity Report itself. Does anyone have any ideas? I'll attach a photo to show you what I mean. The black box is the Device Activity Report that I am trying to edit. Thank you for your help!
Hi Folks,
How to sheild or lock the apps in childs phone from the Guardians Phone.
I got the opaque tokens from childs phone , but on the parents device there are only categories options but not the applications. so how to get the applications in parentsl device . when i try to authorisee the family controls with .individual option there are not the applications in family activity picker but only the categories and others.
Thanks in advance
Hi everyone,
I've been spending my evenings on the app for around 6 months that's using Screen Time API introduced in WWDC 21 (https://developer.apple.com/videos/play/wwdc2021/10123/), I'm having many issues with this API and looking for anyone who has experience with this API, I will appreciate any help or advice I can get!
I'm using DeviceActivityReport to display the dashboard with screen time usage and certain metrics. Device activity report extension runs in an isolated sandbox, which makes it harder to debug and can't make any network call or write to any storage, for privacy purposes which makes sense, but makes it very hard for development.
The issue is that the process where DeviceActivityReport is running crashes for no reason frequently or doesn't run at all. The API itself has many bugs, which is backed up by my experience, Opal app developers and Screen Time even made the news with its bugs. I see the same behaviour with other apps like Opal, but they can workaround somehow it and reload the report.
I'm experienced with UIKit but have little experience with SwiftUI, since ScreenTime API is using SwiftUI only I have to embed DeviceActivityReport in UIKit using UIHostingController and then inside of the device activity report extension target I'm using UIViewControllerRepresentable to embed UIKit into SwiftUI. But I've done some testing and the behaviour is the same when using pure SwiftUI, although there might be fewer hiccups, I couldn't rewrite the whole app.
That's the gist, there's too much code to include, but I can drop more code snippets if there's anyone who has experience with this API who can help me.
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?
Hey,
I am experiencing this bug where I ask the device activity report for data within a date range, in daily segments. the device report receives the truncated date range: some date 23:00 -> some other date 23:00. however the async data list returns date ranges of the sort: 22:00 -> 22:00 (of the next day). and sometimes it returns 22:00 -> 23:00 (of the same day), but then the data contained in that range is still relative to tne entire day since the total screen time is greater than an hour.
I think that the way date intervals are treated by the device activity report extension contains bugs and is not consistent.
Is anyone experiencing similar bugs?
Hello,
I'm currently experiencing an issue with the DeviceActivityMonitor extension in my code, specifically with the eventDidReachThreshold callback. I'm hoping to get some insights into why this problem occurs and how to resolve it.
Problem:
Issue 1: The eventDidReachThreshold callback is not triggering as expected. It appears that the callback is not being invoked when the threshold is reached.
Issue 2: After a few seconds, the eventDidReachThreshold callback starts to trigger multiple times. This unexpected behavior is causing problems in my code, as it results in incorrect actions being taken.
Issue 3: There are instances where the eventDidReachThreshold callback provides an incorrect event name.
iOS version: iOS16.7.2 and iOS17.1.1
Here is my code to start the monitoring:
func startMonitoring() {
var startTime : DateComponents = DateComponents(hour: 0, minute: 0)
let endTime : DateComponents = DateComponents(hour: 23, minute: 59)
/// Creates the schedule for the activity, specifying the start and end times, and setting it to repeat.
let schedule = DeviceActivitySchedule(intervalStart: startTime, intervalEnd: endTime, repeats: true, warningTime: nil)
/// Defines the event that should trigger the encouragement.
let event = DeviceActivityEvent(applications: socialActivitySelection.applicationTokens, categories: socialActivitySelection.categoryTokens, webDomains: socialActivitySelection.webDomainTokens, threshold: DateComponents(minute: 2))
let events: [DeviceActivityEvent.Name: DeviceActivityEvent] = [.socialScreenTimeEvent : event]
do {
activityCenter.stopMonitoring([.socialScreenTime])
/// Tries to start monitoring the activity using the specified schedule and events.
try activityCenter.startMonitoring(.socialScreenTime, during: schedule, events: events)
} catch {
/// Prints an error message if the activity could not be started.
print("Could not start monitoring: \(error)")
}
}
In addition, I should mention that, with each iteration through the eventDidReachThreshold callback, I increment the threshold by 2 minutes and restart the monitoring.
If there are any known workarounds or potential solutions, please share them.
Thank you.
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?
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!
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!
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()
}
}
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?
I created a ShieldConfigurationExtension in Xcode 14.3 with File > New > Target > ShieldConfigurationExtension. This created the extension with all the necessary Info.plist values (correct NSExtensionPrincipalClass, etc.), with the extension included in embedded content in the host app target.
No matter what I try, the extension is not getting invoked when I shield applications from my host app. The custom UI does not show as the shield, and looking at the debugger, an extension process is never invoked.
I am shielding categories like this:
let managedSettings = ManagedSettingsStore()
...
managedSettings.shield.applicationCategories = .all()
And my extension code overrides all the ShieldConfigurationDataSource functions.
class ShieldConfigurationExtension: ShieldConfigurationDataSource {
override func configuration(shielding application: Application) -> ShieldConfiguration {
return ShieldConfiguration(
backgroundBlurStyle: UIBlurEffect.Style.systemThickMaterial,
backgroundColor: UIColor.white,
icon: UIImage(systemName: "stopwatch"),
title: ShieldConfiguration.Label(text: "You are in a Present Session", color: .yellow)
)
}
override func configuration(shielding application: Application, in category: ActivityCategory) -> ShieldConfiguration {
return ShieldConfiguration(
backgroundBlurStyle: UIBlurEffect.Style.systemThickMaterial,
backgroundColor: UIColor.white,
icon: UIImage(systemName: "stopwatch"),
title: ShieldConfiguration.Label(text: "You are in a Present Session", color: .yellow)
)
}
override func configuration(shielding webDomain: WebDomain) -> ShieldConfiguration {
return ShieldConfiguration(
backgroundBlurStyle: UIBlurEffect.Style.systemThickMaterial,
backgroundColor: UIColor.white,
icon: UIImage(systemName: "stopwatch"),
title: ShieldConfiguration.Label(text: "You are in a Present Session", color: .yellow)
)
}
override func configuration(shielding webDomain: WebDomain, in category: ActivityCategory) -> ShieldConfiguration {
return ShieldConfiguration(
backgroundBlurStyle: UIBlurEffect.Style.systemThickMaterial,
backgroundColor: UIColor.white,
icon: UIImage(systemName: "stopwatch"),
title: ShieldConfiguration.Label(text: "You are in a Present Session", color: .yellow)
)
}
}
What am I missing?
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!
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.
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
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!