Our app uses a 24-hour DeviceActivityMonitor repeating schedule to send users notifications for every hour of screen time they spend on their phone per day. Notifications are sent from eventDidReachThreshold callbacks at 1, 2, 3, etc, hour thresholds to keep them aware of their screen time.
We have recently received an influx of emails from our users that after updating to iOS 17.6.1 their DeviceActivityMonitor notifications are saying their screen time was much higher than what is shown in DeviceActivityReport and their device's Screen Time settings.
These users have disabled "Share Across Devices" - but I suspect the DeviceActivityMonitor is still getting screen time from their other devices even though that setting is turned off.
Has anybody else noticed this, understands what is causing this, or could recommend a fix that we can tell our users to do?
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
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!
Topic:
App & System Services
SubTopic:
General
Tags:
Managed Settings
Family Controls
Device Activity
I understand that the DeviceActivityMonitor extension is designed to be very lightweight, and the system terminates the extension as soon as its callback functions return.
However, I want to save values to UserDefaults inside the extension's callback functions. This creates concurrency issues for my app because the documentation for UserDefaults states that "When you set a default value, it’s changed synchronously within your process, and asynchronously to persistent storage and other processes."
In order to guarantee that these values are persisted before the extension terminates my app, I want to call UserDefaults.synchronize(), but its documentations states that it's "unnecessary and shouldn't be used." Furthermore, it's listed under "Legacy" but not marked deprecated.
Is synchronize() the recommended way to solve my concurrency problem? Or could there be a better way to wait for storage synchronization before returning from a synchronous function?
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?
Topic:
App & System Services
SubTopic:
General
Tags:
Extensions
Managed Settings
Family Controls
Device Activity
I am developing an app for iOS 16 using the Xcode 14.0 beta. I've created certificates and provisioning files both through Xcode and manually following instructions at https://developer.apple.com/documentation/xcode/running-your-app-in-the-simulator-or-on-a-device, but every time when trying to install the app on my iPhone 13 Pro Max running iOS 16.0 beta, I get the error The code signature version is no longer supported. Googling around, I haven't found anything funky about code signing with iOS 16 beta, but that might be because it is so new. Is there any reason that my code signature would be invalid given my developer setup? It's attached to my Apple ID and I am a member of the Apple Developer Program. Here's the details to my error if you want to dig in:
Details
Unable to install "Screentox"
Domain: com.apple.dt.MobileDeviceErrorDomain
Code: -402620375
User Info: {
DVTErrorCreationDateKey = "2022-08-02 13:43:50 +0000";
IDERunOperationFailingWorker = IDEInstalliPhoneLauncher;
}
--
The code signature version is no longer supported.
Domain: com.apple.dt.MobileDeviceErrorDomain
Code: -402620375
User Info: {
DVTRadarComponentKey = 487925;
MobileDeviceErrorCode = "(0xE8008029)";
"com.apple.dtdevicekit.stacktrace" = (
0 DTDeviceKitBase 0x0000000122538c30 DTDKCreateNSErrorFromAMDErrorCode + 235
1 DTDeviceKitBase 0x00000001225752ff __90-[DTDKMobileDeviceToken installApplicationBundleAtPath:withOptions:andError:withCallback:]_block_invoke + 155
2 DVTFoundation 0x000000010b7453b5 DVTInvokeWithStrongOwnership + 71
3 DTDeviceKitBase 0x0000000122575027 -[DTDKMobileDeviceToken installApplicationBundleAtPath:withOptions:andError:withCallback:] + 1409
4 IDEiOSSupportCore 0x0000000121f6c66c __118-[DVTiOSDevice(DVTiPhoneApplicationInstallation) processAppInstallSet:appUninstallSet:installOptions:completionBlock:]_block_invoke.301 + 3520
5 DVTFoundation 0x000000010b87a629 __DVT_CALLING_CLIENT_BLOCK__ + 7
6 DVTFoundation 0x000000010b87b13d __DVTDispatchAsync_block_invoke + 196
7 libdispatch.dylib 0x00007ff81d8990cc _dispatch_call_block_and_release + 12
8 libdispatch.dylib 0x00007ff81d89a317 _dispatch_client_callout + 8
9 libdispatch.dylib 0x00007ff81d8a0317 _dispatch_lane_serial_drain + 672
10 libdispatch.dylib 0x00007ff81d8a0dfd _dispatch_lane_invoke + 366
11 libdispatch.dylib 0x00007ff81d8aaeee _dispatch_workloop_worker_thread + 753
12 libsystem_pthread.dylib 0x00007ff81da4dfd0 _pthread_wqthread + 326
13 libsystem_pthread.dylib 0x00007ff81da4cf57 start_wqthread + 15
);
}
--
Analytics Event: com.apple.dt.IDERunOperationWorkerFinished : {
"device_model" = "iPhone14,3";
"device_osBuild" = "16.0 (20A5328h)";
"device_platform" = "com.apple.platform.iphoneos";
"launchSession_schemeCommand" = Run;
"launchSession_state" = 1;
"launchSession_targetArch" = arm64;
"operation_duration_ms" = 4934;
"operation_errorCode" = "-402620375";
"operation_errorDomain" = "com.apple.dt.MobileDeviceErrorDomain";
"operation_errorWorker" = IDEInstalliPhoneLauncher;
"operation_name" = IDEiPhoneRunOperationWorkerGroup;
"param_consoleMode" = 0;
"param_debugger_attachToExtensions" = 0;
"param_debugger_attachToXPC" = 1;
"param_debugger_type" = 5;
"param_destination_isProxy" = 0;
"param_destination_platform" = "com.apple.platform.iphoneos";
"param_diag_MainThreadChecker_stopOnIssue" = 0;
"param_diag_MallocStackLogging_enableDuringAttach" = 0;
"param_diag_MallocStackLogging_enableForXPC" = 1;
"param_diag_allowLocationSimulation" = 1;
"param_diag_gpu_frameCapture_enable" = 0;
"param_diag_gpu_shaderValidation_enable" = 0;
"param_diag_gpu_validation_enable" = 0;
"param_diag_memoryGraphOnResourceException" = 0;
"param_diag_queueDebugging_enable" = 1;
"param_diag_runtimeProfile_generate" = 0;
"param_diag_sanitizer_asan_enable" = 0;
"param_diag_sanitizer_tsan_enable" = 0;
"param_diag_sanitizer_tsan_stopOnIssue" = 0;
"param_diag_sanitizer_ubsan_stopOnIssue" = 0;
"param_diag_showNonLocalizedStrings" = 0;
"param_diag_viewDebugging_enabled" = 1;
"param_diag_viewDebugging_insertDylibOnLaunch" = 1;
"param_install_style" = 0;
"param_launcher_UID" = 2;
"param_launcher_allowDeviceSensorReplayData" = 0;
"param_launcher_kind" = 0;
"param_launcher_style" = 0;
"param_launcher_substyle" = 0;
"param_runnable_appExtensionHostRunMode" = 0;
"param_runnable_productType" = "com.apple.product-type.application";
"param_runnable_type" = 2;
"param_testing_launchedForTesting" = 0;
"param_testing_suppressSimulatorApp" = 0;
"param_testing_usingCLI" = 0;
"sdk_canonicalName" = "iphoneos16.0";
"sdk_osVersion" = "16.0";
"sdk_variant" = iphoneos;
}
--
System Information
macOS Version 12.4 (Build 21F79)
Xcode 14.0 (21304.3) (Build 14A5270f)
Timestamp: 2022-08-02T09:43:50-04:00
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!
For my app, I use the DeviceActivity API to define a daily, repeating DeviceActivitySchedule that begins at 12:00AM and ends at 11:59 PM every day. I notice that when the device is powered off before 11:59 PM and powered back on the next day, neither the intervalDidEnd nor intervalDidStart callback functions are called. It appears that the interval extends into the next day and only ends once 11:59 PM comes around again.
What is the expected behavior of the system to call the intervalDidStart and intervalDidEnd callback functions when the device is powered off during the scheduled start or end time?
Topic:
App & System Services
SubTopic:
General
Tags:
Managed Settings
Family Controls
Device Activity
Screen Time
I've been experiencing some serious performance issues with DeviceActivityReport. Their severity tends to vary across devices - for some of my users it's really bad and for some it's mostly fine - but every device seems to experience these issues at some point.
1. DeviceActivityReport is completely blank. Often on launch, the DeviceActivityReport is completely blank and the only way to make it show up is to click back and forth between tabs, or quit the app and re-open it. Sometimes, it will show up after one or two seconds, but that is still a bad user experience. When looking at logs during this issue, I can see that makeConfiguration still runs successfully and returns a value, so I suspect the issue is with the rendering of the View in the App Extension.
2. Gestures are slow to register, or can't register at all. For example, if I place my DeviceActivityReport inside a ScrollView, I cannot scroll if I perform the gesture on the report view. If I try to scroll on the part of the screen that's not inside the report view, the screen scrolls but it will lag. This makes me think that if I perform a gesture on the report view, only the view inside the App Extension will register the gesture, but not the parent view in my host app. Is that the expected behavior?
My primary concern is number (1), it's by far the biggest pain point for my users and makes my app almost useless to them if they can't view their screen time :(. These issue have been reported before by other developers on the forum (https://developer.apple.com/forums/thread/723444, https://developer.apple.com/forums/thread/723491, https://developer.apple.com/forums/thread/720549).
Instead of recommending that I submit a bug to Feedback Assistant (which I will do), I am kindly asking for some recommendations to work around the known performance issues of DeviceActivityReport. Several apps out there that use the DeviceActivity API that do not appear to have these performance issues, like Opal and Jomo, so they must be doing something right!
One thing I've noticed is that the further up in the View hierarchy the DeviceActivityReport is, the better its performance, but I'm not sure why - maybe it is because the earlier the extension is connected to, the better. My app also has several tabs, makes network requests with asynchronous tasks on launch, uses the DeviceActivityMonitorExtension, and uses CoreData as a local data store. Maybe these things affect performance?
Thank you in advance for any performance recommendations that you could provide!
Hello,
I have an iOS app using the DeviceActivityReport app extension. Occasionally, the extension gets terminated (likely due to reaching memory limit**), which in turn disrupts the connection with the main app.
How can the main app detect when the DeviceActivityReport extension has been terminated due to memory constraints, and what's the best way to re-establish the connection afterward?
Thanks in advance for your insights and suggestions!
** I'm also unsure why the extension should be reaching its memory limit. When profiling the extension in XCode, it never reaches above 15MB, and I know the limit is 100MB. It's not doing anything out of the ordinary - and I've seen very similar complaints about DeviceActivityReport terminating on these forums. Any thoughts on how to prevent termination in the first place would also be super helpful!
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?
Topic:
App & System Services
SubTopic:
General
Tags:
Extensions
Managed Settings
Family Controls
Device 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!
My app monitors DeviceActivityEvents with no categories, apps, or websites selected because we want to monitor their time spent on all categories, apps, and websites. This is because my app gives users rewards for keeping their total Screen Time low.
Unfortunately, it has been seemingly impossible to align the Screen Time shown with DeviceActivityReport to the Screen Time monitored with DeviceActivityMonitor. By default, the DeviceActivityReport captures more Screen Time than the DeviceActivityMonitor by default. But if I try to filter the report by totalActivityDuration on each category, it misses some Screen Time captured by the monitor (like FaceTime, for instance).
I simply want to report to the user exactly the Screen Time I am monitoring by default with DeviceActivityMonitor. Is that possible without selecting any categories, apps, or websites in the monitor?
I am having a lot of trouble reliably making network requests from the DeviceActivityMonitor extension.
In the app extension, when intervalDidEnd is called by the system, I add some data to the app's local CoreData store and sync that with the server. I use URLSession dataTask to make a POST request to my server, with URLSessionConfiguration.sharedContainerIdentifier set to my App Group's shared identifier. It is extremely rare that my server receives this request, although sometimes (rarely) it does.
I've tried things like wrapping the task in performExpiringActivity or using URLSessionConfiguration.background suspecting that this task needs to run in the background, but none of it seems to work.
What I suspect is happening is that the App Extension gets cancelled before the request is able to be invoked. Looking at the console logs, sometimes the work stops before the request is called, sometimes during the request task, and sometimes even before I am able to update my local data store.
It's been very difficult to find any information on the lifecycle of the DeviceActivityMonitor Extension. What I want to know is:
How can I reliably make network requests from the DeviceActivityMonitor Extension?
What is the lifecycle of this extension? (How long do I have to complete work inside callback functions invoked by the system? And can I extend this time if necessary?)
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.
Topic:
App & System Services
SubTopic:
General
Tags:
Extensions
Managed Settings
Family Controls
Device Activity
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?
Topic:
App & System Services
SubTopic:
Core OS
Tags:
iOS
Extensions
Managed Settings
Device Activity